From 85721d3fdcb80ff61eb8c658a1e3a0a360c2b512 Mon Sep 17 00:00:00 2001 From: Mikhail Katliar Date: Sun, 29 Sep 2024 09:51:06 +0200 Subject: [PATCH] Decouple from Blaze - part 2 (#38) - RegisterMatrixTest.testPotrf works - Added reference gemm() implementation - Cleaned-up few other tests in RegisterMatrixTest - Added DynamicMatrix class - Functions trans(), submatrix(), randomize(), makePositiveDefinite() implemented for BLAST matrices - Randomize.hpp moved to blast/math/algorithm. --- bench/blas/Gemm.cpp | 2 +- bench/blas/Iamax.cpp | 2 +- bench/blast/math/dense/DynamicGemm.cpp | 2 +- bench/blast/math/dense/DynamicSyrk.cpp | 2 +- bench/blast/math/dense/StaticGemm.cpp | 2 +- bench/blast/math/dense/StaticGetrf.cpp | 2 +- bench/blast/math/dense/StaticPotrf.cpp | 2 +- bench/blast/math/dense/StaticSyrk.cpp | 2 +- bench/blast/math/dense/StaticTrmm.cpp | 2 +- bench/blast/math/panel/DynamicGemm.cpp | 2 +- bench/blast/math/panel/DynamicPotrf.cpp | 2 +- bench/blast/math/panel/StaticGemm.cpp | 2 +- bench/blast/math/panel/StaticPotrf.cpp | 2 +- bench/blast/math/simd/Ger.cpp | 4 +- bench/blast/math/simd/Load.cpp | 2 +- bench/blast/math/simd/PartialGemm.cpp | 4 +- bench/blast/math/simd/PartialLoad.cpp | 4 +- bench/blast/math/simd/PartialStore.cpp | 4 +- bench/blast/math/simd/Potrf.cpp | 4 +- bench/blast/math/simd/Store.cpp | 2 +- bench/blast/math/simd/Trmm.cpp | 2 +- bench/blast/math/simd/Trsm.cpp | 4 +- bench/blaze/Gemm.cpp | 2 +- bench/blaze/StaticTrmm.cpp | 1 - bench/eigen/Gemm.cpp | 2 +- bench/libxsmm/Gemm.cpp | 2 +- include/blast/math/Matrix.hpp | 13 - include/blast/math/TransposeFlag.hpp | 29 +- include/blast/math/TypeTraits.hpp | 1 + .../math/algorithm/MakePositiveDefinite.hpp | 58 +++ include/blast/math/algorithm/Randomize.hpp | 66 ++++ include/blast/math/dense/DynamicMatrix.hpp | 206 +++++++++++ include/blast/math/dense/StaticMatrix.hpp | 16 + .../blast/math/expressions/MatTransExpr.hpp | 205 +++++++++++ include/blast/math/reference/Gemm.hpp | 93 +++++ include/blast/math/reference/Ger.hpp | 17 +- include/blast/math/typetraits/IsStatic.hpp | 9 + include/blast/math/typetraits/IsView.hpp | 28 ++ .../blast/math/typetraits/VectorPointer.hpp | 4 +- include/blast/math/views/Submatrix.hpp | 280 +++++++++++++++ include/blast/system/Restrict.hpp | 18 + include/test/Randomize.hpp | 32 -- include/test/Testing.hpp | 339 +++++++++--------- test/blast/math/dense/GemmTest.cpp | 2 +- test/blast/math/dense/GerTest.cpp | 2 +- test/blast/math/dense/Getf2Test.cpp | 2 +- test/blast/math/dense/GetrfTest.cpp | 2 +- test/blast/math/dense/Iamax.cpp | 2 +- test/blast/math/dense/PotrfTest.cpp | 2 +- test/blast/math/dense/SyrkTest.cpp | 2 +- test/blast/math/dense/TrmmTest.cpp | 2 +- .../math/expressions/AssignDensePanelTest.cpp | 4 +- .../math/expressions/AssignPanelDenseTest.cpp | 4 +- .../math/expressions/PMatTransExprTest.cpp | 2 +- .../math/panel/DynamicPanelMatrixTest.cpp | 4 +- test/blast/math/panel/GemmTest.cpp | 2 +- test/blast/math/panel/PotrfTest.cpp | 2 +- .../math/panel/StaticPanelMatrixTest.cpp | 2 +- .../math/simd/DynamicRegisterMatrixTest.cpp | 2 +- test/blast/math/simd/RegisterMatrixTest.cpp | 120 +++---- test/blast/math/simd/SimdVecTest.cpp | 2 +- test/blast/math/views/RowTest.cpp | 4 +- test/blast/math/views/SubmatrixTest.cpp | 4 +- 63 files changed, 1281 insertions(+), 364 deletions(-) create mode 100644 include/blast/math/algorithm/MakePositiveDefinite.hpp create mode 100644 include/blast/math/algorithm/Randomize.hpp create mode 100644 include/blast/math/dense/DynamicMatrix.hpp create mode 100644 include/blast/math/expressions/MatTransExpr.hpp create mode 100644 include/blast/math/reference/Gemm.hpp create mode 100644 include/blast/math/typetraits/IsView.hpp create mode 100644 include/blast/system/Restrict.hpp delete mode 100644 include/test/Randomize.hpp diff --git a/bench/blas/Gemm.cpp b/bench/blas/Gemm.cpp index ce07d1b0..613fdca3 100644 --- a/bench/blas/Gemm.cpp +++ b/bench/blas/Gemm.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include diff --git a/bench/blas/Iamax.cpp b/bench/blas/Iamax.cpp index c1b2bc5b..bd04f278 100644 --- a/bench/blas/Iamax.cpp +++ b/bench/blas/Iamax.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include namespace blast :: benchmark diff --git a/bench/blast/math/dense/DynamicGemm.cpp b/bench/blast/math/dense/DynamicGemm.cpp index 10d8fb32..4637dbd5 100644 --- a/bench/blast/math/dense/DynamicGemm.cpp +++ b/bench/blast/math/dense/DynamicGemm.cpp @@ -8,7 +8,7 @@ #include -#include +#include namespace blast :: benchmark diff --git a/bench/blast/math/dense/DynamicSyrk.cpp b/bench/blast/math/dense/DynamicSyrk.cpp index dfb6a3cf..a9811d2b 100644 --- a/bench/blast/math/dense/DynamicSyrk.cpp +++ b/bench/blast/math/dense/DynamicSyrk.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include namespace blast :: benchmark diff --git a/bench/blast/math/dense/StaticGemm.cpp b/bench/blast/math/dense/StaticGemm.cpp index 2565d36a..dab4d93a 100644 --- a/bench/blast/math/dense/StaticGemm.cpp +++ b/bench/blast/math/dense/StaticGemm.cpp @@ -8,7 +8,7 @@ #include -#include +#include namespace blast :: benchmark diff --git a/bench/blast/math/dense/StaticGetrf.cpp b/bench/blast/math/dense/StaticGetrf.cpp index 5b5c0d2d..094a328f 100644 --- a/bench/blast/math/dense/StaticGetrf.cpp +++ b/bench/blast/math/dense/StaticGetrf.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include diff --git a/bench/blast/math/dense/StaticPotrf.cpp b/bench/blast/math/dense/StaticPotrf.cpp index 6073a9e5..cee18eaa 100644 --- a/bench/blast/math/dense/StaticPotrf.cpp +++ b/bench/blast/math/dense/StaticPotrf.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/bench/blast/math/dense/StaticSyrk.cpp b/bench/blast/math/dense/StaticSyrk.cpp index 71a91a02..9ed7e788 100644 --- a/bench/blast/math/dense/StaticSyrk.cpp +++ b/bench/blast/math/dense/StaticSyrk.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include namespace blast :: benchmark diff --git a/bench/blast/math/dense/StaticTrmm.cpp b/bench/blast/math/dense/StaticTrmm.cpp index 1cc263ad..a1350703 100644 --- a/bench/blast/math/dense/StaticTrmm.cpp +++ b/bench/blast/math/dense/StaticTrmm.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace blast :: benchmark diff --git a/bench/blast/math/panel/DynamicGemm.cpp b/bench/blast/math/panel/DynamicGemm.cpp index 3b8866d0..8928d6fc 100644 --- a/bench/blast/math/panel/DynamicGemm.cpp +++ b/bench/blast/math/panel/DynamicGemm.cpp @@ -7,7 +7,7 @@ #include -#include +#include namespace blast :: benchmark diff --git a/bench/blast/math/panel/DynamicPotrf.cpp b/bench/blast/math/panel/DynamicPotrf.cpp index 3179629e..4839e67f 100644 --- a/bench/blast/math/panel/DynamicPotrf.cpp +++ b/bench/blast/math/panel/DynamicPotrf.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/bench/blast/math/panel/StaticGemm.cpp b/bench/blast/math/panel/StaticGemm.cpp index 0c201346..63e6300a 100644 --- a/bench/blast/math/panel/StaticGemm.cpp +++ b/bench/blast/math/panel/StaticGemm.cpp @@ -9,7 +9,7 @@ #include -#include +#include namespace blast :: benchmark diff --git a/bench/blast/math/panel/StaticPotrf.cpp b/bench/blast/math/panel/StaticPotrf.cpp index 4929837a..26298bd7 100644 --- a/bench/blast/math/panel/StaticPotrf.cpp +++ b/bench/blast/math/panel/StaticPotrf.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/bench/blast/math/simd/Ger.cpp b/bench/blast/math/simd/Ger.cpp index dee889a7..c099c8e0 100644 --- a/bench/blast/math/simd/Ger.cpp +++ b/bench/blast/math/simd/Ger.cpp @@ -7,7 +7,7 @@ #include -#include +#include namespace blast :: benchmark @@ -53,4 +53,4 @@ namespace blast :: benchmark BENCHMARK_TEMPLATE(BM_RegisterMatrix_ger_nt, float, 24, 4, columnMajor); BENCHMARK_TEMPLATE(BM_RegisterMatrix_ger_nt, float, 16, 5, columnMajor); BENCHMARK_TEMPLATE(BM_RegisterMatrix_ger_nt, float, 16, 6, columnMajor); -} \ No newline at end of file +} diff --git a/bench/blast/math/simd/Load.cpp b/bench/blast/math/simd/Load.cpp index 104653ae..c5ededc1 100644 --- a/bench/blast/math/simd/Load.cpp +++ b/bench/blast/math/simd/Load.cpp @@ -9,7 +9,7 @@ #include -#include +#include #include diff --git a/bench/blast/math/simd/PartialGemm.cpp b/bench/blast/math/simd/PartialGemm.cpp index a62a69de..84951e6f 100644 --- a/bench/blast/math/simd/PartialGemm.cpp +++ b/bench/blast/math/simd/PartialGemm.cpp @@ -8,7 +8,7 @@ #include -#include +#include #include @@ -47,4 +47,4 @@ namespace blast :: benchmark BENCHMARK_TEMPLATE(BM_RegisterMatrix_partialGemm_static, double, 4, 4, columnMajor, 3, 4); BENCHMARK_TEMPLATE(BM_RegisterMatrix_partialGemm_static, double, 4, 4, columnMajor, 4, 4); BENCHMARK_TEMPLATE(BM_RegisterMatrix_partialGemm_static, double, 4, 4, columnMajor, 1, 1); -} \ No newline at end of file +} diff --git a/bench/blast/math/simd/PartialLoad.cpp b/bench/blast/math/simd/PartialLoad.cpp index 48db98dd..35bd52ea 100644 --- a/bench/blast/math/simd/PartialLoad.cpp +++ b/bench/blast/math/simd/PartialLoad.cpp @@ -8,7 +8,7 @@ #include -#include +#include #include @@ -121,4 +121,4 @@ namespace blast :: benchmark // BENCHMARK_TEMPLATE(BM_RegisterMatrix_partialStore_static, double, 4, 4, columnMajor, 1, 4); // BENCHMARK_TEMPLATE(BM_RegisterMatrix_partialStore_static, double, 4, 4, columnMajor, 2, 4); -} \ No newline at end of file +} diff --git a/bench/blast/math/simd/PartialStore.cpp b/bench/blast/math/simd/PartialStore.cpp index 7b5f3c4a..10f42145 100644 --- a/bench/blast/math/simd/PartialStore.cpp +++ b/bench/blast/math/simd/PartialStore.cpp @@ -8,7 +8,7 @@ #include -#include +#include #include @@ -171,4 +171,4 @@ namespace blast :: benchmark BENCHMARK_TEMPLATE(BM_RegisterMatrix_partialStore_static, double, 4, 4, columnMajor, 1, 4); BENCHMARK_TEMPLATE(BM_RegisterMatrix_partialStore_static, double, 4, 4, columnMajor, 2, 4); -} \ No newline at end of file +} diff --git a/bench/blast/math/simd/Potrf.cpp b/bench/blast/math/simd/Potrf.cpp index 50672ae2..0f44ab52 100644 --- a/bench/blast/math/simd/Potrf.cpp +++ b/bench/blast/math/simd/Potrf.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include namespace blast :: benchmark @@ -46,4 +46,4 @@ namespace blast :: benchmark BENCHMARK_TEMPLATE(BM_RegisterMatrix_potrf, float, 8, 4, columnMajor); BENCHMARK_TEMPLATE(BM_RegisterMatrix_potrf, float, 16, 4, columnMajor); BENCHMARK_TEMPLATE(BM_RegisterMatrix_potrf, float, 24, 4, columnMajor); -} \ No newline at end of file +} diff --git a/bench/blast/math/simd/Store.cpp b/bench/blast/math/simd/Store.cpp index 4e11a498..398a5aa5 100644 --- a/bench/blast/math/simd/Store.cpp +++ b/bench/blast/math/simd/Store.cpp @@ -9,7 +9,7 @@ #include -#include +#include #include diff --git a/bench/blast/math/simd/Trmm.cpp b/bench/blast/math/simd/Trmm.cpp index 5cc29978..ef660139 100644 --- a/bench/blast/math/simd/Trmm.cpp +++ b/bench/blast/math/simd/Trmm.cpp @@ -7,7 +7,7 @@ #include -#include +#include #include diff --git a/bench/blast/math/simd/Trsm.cpp b/bench/blast/math/simd/Trsm.cpp index ec58fc2b..85f050b6 100644 --- a/bench/blast/math/simd/Trsm.cpp +++ b/bench/blast/math/simd/Trsm.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include namespace blast :: benchmark @@ -44,4 +44,4 @@ namespace blast :: benchmark BENCHMARK_TEMPLATE(BM_RegisterMatrix_trsm, double, 8, 4, columnMajor); BENCHMARK_TEMPLATE(BM_RegisterMatrix_trsm, double, 12, 4, columnMajor); BENCHMARK_TEMPLATE(BM_RegisterMatrix_trsm, double, 8, 8, columnMajor); -} \ No newline at end of file +} diff --git a/bench/blaze/Gemm.cpp b/bench/blaze/Gemm.cpp index 157b0c73..7705c05e 100644 --- a/bench/blaze/Gemm.cpp +++ b/bench/blaze/Gemm.cpp @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. #include -#include +#include #include diff --git a/bench/blaze/StaticTrmm.cpp b/bench/blaze/StaticTrmm.cpp index 51ec7393..28d4cf73 100644 --- a/bench/blaze/StaticTrmm.cpp +++ b/bench/blaze/StaticTrmm.cpp @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. #include -#include #include diff --git a/bench/eigen/Gemm.cpp b/bench/eigen/Gemm.cpp index 0be8a3c3..ea6f37fa 100644 --- a/bench/eigen/Gemm.cpp +++ b/bench/eigen/Gemm.cpp @@ -10,7 +10,7 @@ #include -#include +#include #include diff --git a/bench/libxsmm/Gemm.cpp b/bench/libxsmm/Gemm.cpp index 2fa9388d..5028e768 100644 --- a/bench/libxsmm/Gemm.cpp +++ b/bench/libxsmm/Gemm.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include diff --git a/include/blast/math/Matrix.hpp b/include/blast/math/Matrix.hpp index 7dcb0228..f5da1512 100644 --- a/include/blast/math/Matrix.hpp +++ b/include/blast/math/Matrix.hpp @@ -14,7 +14,6 @@ #include #include -#include namespace blast @@ -49,18 +48,6 @@ namespace blast { return ptr>(m, 0, 0); } - - - template - inline void randomize(M& m) noexcept - { - std::mt19937 rng; - std::uniform_real_distribution> dist; - - for (size_t i = 0; i < rows(m); ++i) - for (size_t j = 0; j < columns(m); ++j) - m(i, j) = dist(rng); - } template diff --git a/include/blast/math/TransposeFlag.hpp b/include/blast/math/TransposeFlag.hpp index 4018b846..47a06fdf 100644 --- a/include/blast/math/TransposeFlag.hpp +++ b/include/blast/math/TransposeFlag.hpp @@ -1,28 +1,21 @@ -// Copyright 2023 Mikhail Katliar -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Copyright 2023-2024 Mikhail Katliar. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. #pragma once -#include - namespace blast { + /** + * @brief Defines whether a vector is a row or a column + * + * The bool values match those of @a blaze::TransposeFlag + */ enum TransposeFlag : bool { - rowVector = blaze::rowVector, - columnVector = blaze::columnVector + rowVector = true, + columnVector = false }; @@ -30,4 +23,4 @@ namespace blast { return tf == TransposeFlag::rowVector ? TransposeFlag::columnVector : TransposeFlag::rowVector; } -} \ No newline at end of file +} diff --git a/include/blast/math/TypeTraits.hpp b/include/blast/math/TypeTraits.hpp index bff67adc..893e6301 100644 --- a/include/blast/math/TypeTraits.hpp +++ b/include/blast/math/TypeTraits.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/include/blast/math/algorithm/MakePositiveDefinite.hpp b/include/blast/math/algorithm/MakePositiveDefinite.hpp new file mode 100644 index 00000000..27da3542 --- /dev/null +++ b/include/blast/math/algorithm/MakePositiveDefinite.hpp @@ -0,0 +1,58 @@ +// Copyright 2024 Mikhail Katliar. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +//************************************************************************************************* +#pragma once + +#include +#include +#include +#include +#include +#include + + +namespace blast +{ + /** + * @brief Setup of a random positive definite @a Matrix. + * + * @param matrix The matrix to be randomized. + * + * @throw @a std::invalid_argument if non-square matrix is provided + */ + template + inline void makePositiveDefinite(MT& matrix) + { + using ET = ElementType_t; + + size_t const N = columns(matrix); + if (rows(matrix) != N) + BLAST_THROW_EXCEPTION(std::invalid_argument {"Non-square matrix provided"}); + + DynamicMatrix tmp(N, N); + randomize(tmp); + + reset(matrix); + reference::gemm(ET(1), tmp, trans(tmp), ET(0), matrix, matrix); + + for (size_t i = 0; i < N; ++i) + matrix(i, i) += ET(N); + } + + + /** + * @brief Setup of a random positive definite matrix, + * specialized for rvalue reverence to matrix views. + * + * @param matrix The matrix to be randomized. + * + * @throw @a std::invalid_argument if non-square matrix is provided + */ + template + requires IsView_v + inline void makePositiveDefinite(MT&& matrix) + { + makePositiveDefinite(matrix); + } +} diff --git a/include/blast/math/algorithm/Randomize.hpp b/include/blast/math/algorithm/Randomize.hpp new file mode 100644 index 00000000..6b76c46f --- /dev/null +++ b/include/blast/math/algorithm/Randomize.hpp @@ -0,0 +1,66 @@ +// Copyright (c) 2019-2020 Mikhail Katliar All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#pragma once + +#include + +#include +#include +#include + + +namespace blast +{ + namespace detail + { + inline auto& randomEngine() + { + static std::mt19937 engine; + return engine; + } + } + + + template + requires std::is_floating_point_v + inline void randomize(T& a) + { + std::uniform_real_distribution dist; + a = dist(detail::randomEngine()); + } + + + template + inline void randomize(std::array& a) + { + for (T& v : a) + randomize(v); + } + + + template + inline void randomize(std::vector& a) + { + for (T& v : a) + randomize(v); + } + + + template + inline void randomize(M& m) noexcept + { + for (size_t i = 0; i < rows(m); ++i) + for (size_t j = 0; j < columns(m); ++j) + randomize(m(i, j)); + } + + + template + requires IsView_v + inline void randomize(M&& m) noexcept + { + randomize(m); + } +} diff --git a/include/blast/math/dense/DynamicMatrix.hpp b/include/blast/math/dense/DynamicMatrix.hpp new file mode 100644 index 00000000..0b6128d9 --- /dev/null +++ b/include/blast/math/dense/DynamicMatrix.hpp @@ -0,0 +1,206 @@ +// Copyright (c) 2019-2020 Mikhail Katliar All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace blast +{ + /// @brief Row/column major matrix with dynamically defined size. + /// + /// @tparam T element type of the matrix + /// @tparam SO storage order of panel elements + /// + template + class DynamicMatrix + { + public: + using ElementType = T; + + + explicit DynamicMatrix(size_t m, size_t n) + : m_ {m} + , n_ {n} + , spacing_ {nextMultiple(SO == columnMajor ? m : n, SimdSize_v)} + // Initialize padding elements to 0 to prevent denorms in calculations. + // Denorms can significantly impair performance, see https://github.com/giaf/blasfeo/issues/103 + , v_ {new(std::align_val_t {alignment_}) T[spacing_ * (SO == columnMajor ? n : m)] {}} + { + } + + + DynamicMatrix(DynamicMatrix const& rhs) + { + throw std::logic_error {"Not implemented"}; + } + + + DynamicMatrix(DynamicMatrix&& rhs) noexcept + { + throw std::logic_error {"Not implemented"}; + } + + + ~DynamicMatrix() + { + delete[] v_; + } + + + DynamicMatrix& operator=(T val) noexcept + { + for (size_t i = 0; i < m_; ++i) + for (size_t j = 0; j < n_; ++j) + (*this)(i, j) = val; + + return *this; + } + + + DynamicMatrix& operator=(DynamicMatrix const& val) + { + throw std::logic_error {"Not implemented"}; + return *this; + } + + + DynamicMatrix& operator=(DynamicMatrix&& val) noexcept + { + throw std::logic_error {"Not implemented"}; + return *this; + } + + + T const& operator()(size_t i, size_t j) const noexcept + { + return v_[elementIndex(i, j)]; + } + + + T& operator()(size_t i, size_t j) noexcept + { + return v_[elementIndex(i, j)]; + } + + + size_t rows() const noexcept + { + return m_; + } + + + size_t columns() const noexcept + { + return n_; + } + + + size_t spacing() const noexcept + { + return spacing_; + } + + + T * data() noexcept + { + return v_; + } + + + T const * data() const noexcept + { + return v_; + } + + + /** + * @brief Set all matrix elements to 0 + */ + void reset() noexcept + { + std::fill_n(v_, spacing_ * (SO == columnMajor ? n_ : m_), T {}); + } + + + private: + static size_t constexpr alignment_ = CACHE_LINE_SIZE; + static size_t constexpr SS = SimdSize_v; + + size_t m_; + size_t n_; + size_t spacing_; + T * BLAST_RESTRICT v_; + + + size_t elementIndex(size_t i, size_t j) const noexcept + { + return SO == columnMajor ? i + j * spacing_ : i * spacing_ + j; + } + }; + + + template + inline size_t constexpr rows(DynamicMatrix const& m) noexcept + { + return m.rows(); + } + + + template + inline size_t constexpr columns(DynamicMatrix const& m) noexcept + { + return m.columns(); + } + + + template + inline size_t constexpr spacing(DynamicMatrix const& m) noexcept + { + return m.spacing(); + } + + + template + inline constexpr T * data(DynamicMatrix& m) noexcept + { + return m.data(); + } + + + template + inline constexpr T const * data(DynamicMatrix const& m) noexcept + { + return m.data(); + } + + + template + inline void reset(DynamicMatrix& m) noexcept + { + m.reset(); + } + + + template + struct IsDenseMatrix> : std::true_type {}; + + + template + struct IsStatic> : std::false_type {}; + + + template + struct StorageOrderHelper> : std::integral_constant {}; +} diff --git a/include/blast/math/dense/StaticMatrix.hpp b/include/blast/math/dense/StaticMatrix.hpp index 2cb4c344..c000483f 100644 --- a/include/blast/math/dense/StaticMatrix.hpp +++ b/include/blast/math/dense/StaticMatrix.hpp @@ -138,6 +138,15 @@ namespace blast } + /** + * @brief Set all matrix elements to 0 + */ + void reset() noexcept + { + std::fill_n(v_, capacity_, T {}); + } + + private: static size_t constexpr spacing_ = nextMultiple(SO == columnMajor ? M : N, SimdSize_v); static size_t constexpr capacity_ = spacing_ * (SO == columnMajor ? N : M); @@ -184,6 +193,13 @@ namespace blast } + template + inline void reset(StaticMatrix& m) noexcept + { + m.reset(); + } + + template struct IsDenseMatrix> : std::true_type {}; diff --git a/include/blast/math/expressions/MatTransExpr.hpp b/include/blast/math/expressions/MatTransExpr.hpp new file mode 100644 index 00000000..7224af21 --- /dev/null +++ b/include/blast/math/expressions/MatTransExpr.hpp @@ -0,0 +1,205 @@ +// Copyright (c) 2019-2020 Mikhail Katliar All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#pragma once + +#include +#include + +#include +#include + + +namespace blast +{ + /** + * @brief Expression object for matrix transpositions + * + * @tparam MT type of the matrix being transposed + * + */ + template + class MatTransExpr + { + public: + using ElementType = ElementType_t; + using Operand = MT const; + + explicit MatTransExpr(MT const& matrix) noexcept + : m_ {matrix} + {} + + + /** + * @brief 2D-access to the matrix elements. + * + * @param i Access index for the row. The index has to be in the range \f$[0..M-1]\f$. + * @param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$. + * + * @return The resulting value. + */ + ElementType operator()(size_t i, size_t j) const noexcept + { + assert(i < columns(m_)); + assert(j < rows(m_)); + return m_(j, i); + } + + + /** + * @brief Number of rows + * + * @param e matrix transpose expression + * + * @return The number of rows of the transpose expression. + */ + friend size_t rows(MatTransExpr const& e) noexcept + { + return columns(e.m_); + } + + + /** + * @brief Number of columns + * + * @param e matrix transpose expression + * + * @return The number of columns of the transpose expression. + */ + friend size_t columns(MatTransExpr const& e) noexcept + { + return rows(e.m_); + } + + + /** + * @brief Pointer to the data + * + * @param e matrix transpose expression + * + * @return Pointer to matrix data + */ + friend ElementType * data(MatTransExpr& e) noexcept + { + return data(e.m_); + } + + + /** + * @brief Constant pointer to the data + * + * @param e matrix transpose expression + * + * @return Constant pointer to matrix data + */ + friend ElementType const * data(MatTransExpr const& e) noexcept + { + return data(e.m_); + } + + + /** + * @brief Returns the spacing of the underlying matrix storage. + * + * @param e matrix transpose expression + * + * @return The spacing of the underlying matrix storage. + */ + friend size_t spacing(MatTransExpr const& e) noexcept + { + return spacing(e.m_); + } + + + /** + * @brief Returns the matrix operand. + * + * @return The matrix operand. + */ + Operand const& operand() const noexcept + { + return m_; + } + + private: + Operand& m_; + }; + + + /** + * @brief Transpose of a matrix + * + * @tparam MT matrix type + * + * @param m matrix + * + * @return expression representing the transposition of the matrix + */ + template + inline auto trans(MT const& m) + { + return MatTransExpr {m}; + } + + + /** + * @brief Transpose of a transpose + * + * @tparam MT matrix type + * + * @param e matrix transposition expression + * + * @return the operand of the transposition expression + */ + template + inline decltype(auto) trans(MatTransExpr const& e) + { + return e.operand(); + } + + + /** + * @brief Specialization for @a MatTransExpr + * + * @tparam MT expression operand type + */ + template + struct IsAligned> : IsAligned {}; + + + /** + * @brief Specialization for @a MatTransExpr + * + * @tparam MT expression operand type + */ + template + struct IsStatic> : IsStatic {}; + + + /** + * @brief Specialization for @a MatTransExpr + * + * @tparam MT expression operand type + */ + template + struct IsDenseMatrix> : IsDenseMatrix {}; + + + /** + * @brief Specialization for @a MatTransExpr + * + * @tparam MT expression operand type + */ + template + struct Spacing> : Spacing {}; + + + /** + * @brief Specialization for @a MatTransExpr + * + * @tparam MT expression operand type + */ + template + struct StorageOrderHelper> : std::integral_constant> {}; +} diff --git a/include/blast/math/reference/Gemm.hpp b/include/blast/math/reference/Gemm.hpp new file mode 100644 index 00000000..671656a0 --- /dev/null +++ b/include/blast/math/reference/Gemm.hpp @@ -0,0 +1,93 @@ +// Copyright (c) 2019-2020 Mikhail Katliar All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#pragma once + +#include +#include + + +namespace blast :: reference +{ + /** + * @brief Reference implementation of general matrix-matrix multiplication with @a MatrixPointer arguments + * + * D := alpha*A*B + beta*C + * + * alpha and beta are scalars, and A, B and C are matrices, with A + * an m by k matrix, B a k by n matrix and C an m by n matrix. + * + * @tparam ST1 scalar type for @a alpha + * @tparam MPA matrix pointer type for @a A + * @tparam MPB matrix pointer type for @a B + * @tparam ST2 scalar type for @a beta + * @tparam MPC matrix pointer type for @a C + * @tparam MPD matrix pointer type for @a D + * + * @param M the number of rows of the matrices A, C, and D. + * @param N the number of columns of the matrices B and C. + * @param K the number of columns of the matrix A and the number of rows of the matrix B. + * @param alpha the scalar alpha + * @param A the matrix A + * @param B the matrix B + * @param beta the scalar beta + * @param C the matrix C + * @param D the output matrix D + */ + template < + typename ST1, MatrixPointer MPA, MatrixPointer MPB, + typename ST2, MatrixPointer MPC, MatrixPointer MPD + > + inline void gemm(size_t M, size_t N, size_t K, ST1 alpha, MPA A, MPB B, ST2 beta, MPC C, MPD D) + { + using ET = ElementType_t; + + for (size_t i = 0; i < M; ++i) + { + for (size_t j = 0; j < N; ++j) + { + ET v {}; + for (size_t k = 0; k < K; ++k) + v += *(~A)(i, k) * *(~B)(k, j); + + *(~D)(i, j) = alpha * v + beta * *(~C)(i, j); + } + } + } + + + /** + * @brief Reference implementation of general matrix-matrix multiplication for generic matrix arguments + * + * D := alpha*A*B + beta*C + * + * alpha and beta are scalars, and A, B and C are matrices, with A + * an m by k matrix, B a k by n matrix and C an m by n matrix. + * + * @param alpha the scalar alpha + * @param A the matrix A + * @param B the matrix B + * @param beta the scalar beta + * @param C the matrix C + * @param D the output matrix D + */ + template + inline void gemm(ST1 alpha, MT1 const& A, MT2 const& B, ST2 beta, MT3 const& C, MT4& D) + { + size_t const M = rows(A); + size_t const N = columns(B); + size_t const K = columns(A); + + if (rows(B) != K) + BLAST_THROW_EXCEPTION(std::invalid_argument {"Matrix sizes do not match"}); + + if (rows(C) != M || columns(C) != N) + BLAST_THROW_EXCEPTION(std::invalid_argument {"Matrix sizes do not match"}); + + if (rows(D) != M || columns(D) != N) + BLAST_THROW_EXCEPTION(std::invalid_argument {"Matrix sizes do not match"}); + + gemm(M, N, K, alpha, ptr(A), ptr(B), beta, ptr(C), ptr(D)); + } +} diff --git a/include/blast/math/reference/Ger.hpp b/include/blast/math/reference/Ger.hpp index 04774ebc..eeebd43e 100644 --- a/include/blast/math/reference/Ger.hpp +++ b/include/blast/math/reference/Ger.hpp @@ -3,8 +3,7 @@ // license that can be found in the LICENSE file. #pragma once -#include -#include +#include #include @@ -13,13 +12,14 @@ namespace blast :: reference /** * @brief Reference implementation of rank-1 update with multiplier * - * a(i, j) += alpha * x(i) * y(j) + * b(i, j) = a(i, j) + alpha * x(i) * y(j) * for i=0...m-1, j=n-1 * * @tparam Real real number type * @tparam VPX vector pointer type for the column vector @a x * @tparam VPY vector pointer type for the row vector @a y - * @tparam MPA + * @tparam MPA matrix pointer type for the matrix @a a + * @tparam MPB matrix pointer type for the matrix @a b * * @param m number of rows in the matrix * @param n number of columns in the matrix @@ -29,12 +29,13 @@ namespace blast :: reference * @param a matrix to perform update on * */ - template - requires VectorPointer && VectorPointer && MatrixPointer - inline void ger(size_t m, size_t n, Real alpha, VPX x, VPY y, MPA a) + template + requires VectorPointer && VectorPointer && MatrixPointer && MatrixPointer + // && VPX::transposeFlag == columnVector && VPY::transposeFlag == rowVector + inline void ger(size_t m, size_t n, Real alpha, VPX x, VPY y, MPA a, MPB b) { for (size_t i = 0; i < m; ++i) for (size_t j = 0; j < n; ++j) - *(~a)(i, j) += alpha * *(~x)(i) * *(~y)(j); + *(~b)(i, j) = *(~a)(i, j) + alpha * *(~x)(i) * *(~y)(j); } } diff --git a/include/blast/math/typetraits/IsStatic.hpp b/include/blast/math/typetraits/IsStatic.hpp index a6bb784b..a0bf1a0e 100644 --- a/include/blast/math/typetraits/IsStatic.hpp +++ b/include/blast/math/typetraits/IsStatic.hpp @@ -16,6 +16,15 @@ namespace blast struct IsStatic; + /** + * @brief Specialization for const types + * + * @tparam T matrix or vector type + */ + template + struct IsStatic : IsStatic {}; + + /** * @brief Shortcut for @a IsStatic::value * diff --git a/include/blast/math/typetraits/IsView.hpp b/include/blast/math/typetraits/IsView.hpp new file mode 100644 index 00000000..530bc165 --- /dev/null +++ b/include/blast/math/typetraits/IsView.hpp @@ -0,0 +1,28 @@ +// Copyright 2024 Mikhail Katliar. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#pragma once + +#include + + +namespace blast +{ + /** + * @brief Tests if the given matrix or vector type is a view. + * + * @tparam T matrix or vector type + */ + template + struct IsView : std::integral_constant {}; + + + /** + * @brief Shortcut for @a IsView::value + * + * @tparam T matrix or vector type + */ + template + bool constexpr IsView_v = IsView::value; +} diff --git a/include/blast/math/typetraits/VectorPointer.hpp b/include/blast/math/typetraits/VectorPointer.hpp index 9a876129..b6783817 100644 --- a/include/blast/math/typetraits/VectorPointer.hpp +++ b/include/blast/math/typetraits/VectorPointer.hpp @@ -23,5 +23,7 @@ namespace blast *p; // {p.get()} -> std::same_as; + + P::transposeFlag; }; -} \ No newline at end of file +} diff --git a/include/blast/math/views/Submatrix.hpp b/include/blast/math/views/Submatrix.hpp index 9446d61c..a249ff52 100644 --- a/include/blast/math/views/Submatrix.hpp +++ b/include/blast/math/views/Submatrix.hpp @@ -6,3 +6,283 @@ #include #include +#include + +#include + + +namespace blast +{ + /** + * @brief Submatrix view of a matrix + * + * @tparam MT viewed matrix type + * @tparam AF whether the submatrix lop left element is aligned + */ + template + class Submatrix + { + public: + using ViewedType = MT; + using ElementType = ElementType_t; + + //! Reference to a constant submatrix value. + using ConstReference = ElementType const&; + + //! Reference to a non-constant submatrix value. + using Reference = std::conditional_t, ConstReference, ElementType&>; + + //! Pointer to a constant submatrix value. + using ConstPointer = ElementType const *; + + //! Pointer to a non-constant submatrix value. + using Pointer = std::conditional_t, ConstPointer, ElementType *>; + + + /** + * @brief Constructor + * + * @param i top row index of the submatrix + * @param j left column index of the submatrix + * @param m number of rows of the submatrix + * @param n number of columns of the submatrix + */ + explicit inline constexpr Submatrix(MT& matrix, size_t i, size_t j, size_t m, size_t n) + : matrix_ {matrix} + , i_ {i} + , j_ {j} + , m_ {m} + , n_ {n} + , data_ {&matrix_(i_, j_)} + { + BLAST_USER_ASSERT(i_ + m_ <= rows(matrix_), "Invalid submatrix specification"); + BLAST_USER_ASSERT(j_ + n_ <= columns(matrix_), "Invalid submatrix specification"); + } + + + Submatrix(Submatrix const&) = default; + + + /** + * @brief Matrix assignment + * + * Copies elements from the right-hand side expression + * + * @tparam MT2 type of right-hand side matrix + * + * @param rhs + * + * @return reference to *this + */ + template + Submatrix& operator=(MT2 const& rhs) + { + assign(*this, rhs); + return *this; + } + + + size_t constexpr row() const noexcept + { + return i_; + }; + + + size_t constexpr column() const noexcept + { + return j_; + }; + + + friend size_t constexpr rows(Submatrix const& m) noexcept + { + return m.m_; + }; + + + friend size_t constexpr columns(Submatrix const& m) noexcept + { + return m.n_; + }; + + + MT& operand() noexcept + { + return matrix_; + } + + + const MT& operand() const noexcept + { + return matrix_; + } + + + friend size_t spacing(Submatrix const& m) noexcept + { + return spacing(m.matrix_); + } + + + Reference operator()(size_t i, size_t j) noexcept + { + BLAST_USER_ASSERT(i < m_, "Invalid row access index"); + BLAST_USER_ASSERT(j < n_, "Invalid column access index"); + + return matrix_(i_ + i, j_ + j); + } + + + ConstReference operator()( size_t i, size_t j ) const + { + BLAST_USER_ASSERT(i < m_, "Invalid row access index"); + BLAST_USER_ASSERT(j < n_, "Invalid column access index"); + + return const_cast(matrix_)(i_ + i, j_ + j); + } + + + friend Pointer data(Submatrix& m) noexcept + { + return m.data_; + } + + + friend ConstPointer data(Submatrix const& m) noexcept + { + return m.data_; + } + + + private: + ViewedType& matrix_; //!< The matrix containing the submatrix. + size_t const i_; + size_t const j_; + size_t const m_; + size_t const n_; + + // Pointer to the first element of the submatrix + Pointer const data_; + }; + + + /** + * @brief Specialization for @a Submatrix class + */ + template + struct IsAligned> : std::integral_constant {}; + + + /** + * @brief Specialization for @a Submatrix class + */ + template + struct IsStatic> : IsStatic {}; + + + /** + * @brief Specialization for @a Submatrix class + */ + template + struct IsDenseMatrix> : IsDenseMatrix {}; + + + /** + * @brief Specialization for @a Submatrix class + */ + template + struct IsView> : std::integral_constant {}; + + + /** + * @brief Specialization for @a Submatrix class + */ + template + struct Spacing> : Spacing {}; + + + /** + * @brief Specialization for @a Submatrix class + */ + template + struct StorageOrderHelper> : StorageOrderHelper {}; + + + /** + * @brief Submatrix of a matrix + * + * @tparam AF alignment flag of the resulting submatrix + * @tparam MT type of the matrix containing the submatrix + * + * @param matrix matrix containing the submatrix + * @param row top row index of the submatrix + * @param column left column index of the submatrix + * @param m number of rows in the resulting submatrix + * @param n number of columns in the resulting submatrix + * + * @return submatrix of @a matrix + */ + template + inline decltype(auto) submatrix(MT& matrix, size_t row, size_t column, size_t m, size_t n) + { + return Submatrix {matrix, row, column, m, n}; + } + + + /** + * @brief Submatrix of a const @a Submatrix + * + * @tparam AF alignment flag of the resulting submatrix + * @tparam MT type of the matrix containing the submatrix + * @tparam AF1 alignment flag of the matrix containing the submatrix + * + * @param matrix matrix containing the submatrix + * @param row top row index of the submatrix (relative to @a matrix) + * @param column left column index of the submatrix (relative to @a matrix) + * @param m number of rows in the resulting submatrix + * @param n number of columns in the resulting submatrix + * + * @return submatrix of @a matrix + */ + template + inline decltype(auto) submatrix(Submatrix const& matrix, size_t row, size_t column, size_t m, size_t n) + { + return Submatrix {matrix.operand(), matrix.row() + row, matrix.column() + column, m, n}; + } + + + /** + * @brief Submatrix of a @a Submatrix + * + * @tparam AF alignment flag of the resulting submatrix + * @tparam MT type of the matrix containing the submatrix + * @tparam AF1 alignment flag of the matrix containing the submatrix + * + * @param matrix matrix containing the submatrix + * @param row top row index of the submatrix (relative to @a matrix) + * @param column left column index of the submatrix (relative to @a matrix) + * @param m number of rows in the resulting submatrix + * @param n number of columns in the resulting submatrix + * + * @return submatrix of @a matrix + */ + template + inline decltype(auto) submatrix(Submatrix& matrix, size_t row, size_t column, size_t m, size_t n) + { + return Submatrix {matrix.operand(), matrix.row() + row, matrix.column() + column, m, n}; + } + + + /** + * @brief Set all elements of a submatrix to their default value (0). + * + * @param matrix submatrix to set to 0. + */ + template + inline void reset(Submatrix& matrix) noexcept + { + for (size_t i = 0; i < rows(matrix); ++i) + for (size_t j = 0; j < columns(matrix); ++j) + matrix(i, j) = ElementType_t {}; + } +} diff --git a/include/blast/system/Restrict.hpp b/include/blast/system/Restrict.hpp new file mode 100644 index 00000000..9e114529 --- /dev/null +++ b/include/blast/system/Restrict.hpp @@ -0,0 +1,18 @@ +#pragma once + +// Intel compiler +#if defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC) +# define BLAST_RESTRICT __restrict + +// GNU compiler +#elif defined(__GNUC__) +# define BLAST_RESTRICT __restrict + +// Microsoft visual studio +#elif defined(_MSC_VER) +# define BLAST_RESTRICT __restrict + +// All other compilers +#else +# define BLAST_RESTRICT +# endif diff --git a/include/test/Randomize.hpp b/include/test/Randomize.hpp deleted file mode 100644 index 070e4e55..00000000 --- a/include/test/Randomize.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2019-2020 Mikhail Katliar All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#pragma once - -#include - -#include -#include - - -namespace blast -{ - using blaze::randomize; - - - template - inline void randomize(std::array& a) - { - for (T& v : a) - blaze::randomize(v); - } - - - template - inline void randomize(std::vector& a) - { - for (T& v : a) - blaze::randomize(v); - } -} diff --git a/include/test/Testing.hpp b/include/test/Testing.hpp index 2802ab79..7aaef82f 100644 --- a/include/test/Testing.hpp +++ b/include/test/Testing.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -18,191 +19,191 @@ namespace blast :: testing { - using namespace ::testing; - - - namespace detail - { - template - class ForcePrintImpl - : public T - { - friend void PrintTo(const ForcePrintImpl &m, ::std::ostream *o) - { - *o << "\n" << m; - } - }; - } - - - /* - * Makes the Eigen3 matrix classes printable from GTest checking macros like EXPECT_EQ. - * Usage: EXPECT_EQ(forcePrint(a), forcePrint(b)) - * Taken from this post: http://stackoverflow.com/questions/25146997/teach-google-test-how-to-print-eigen-matrix - */ - template - decltype(auto) forcePrint(T const& val) - { - return static_cast const&>(val); - } - - - MATCHER_P(FloatNearPointwise, tol, "Out of range") - { - return (std::get<0>(arg) > std::get<1>(arg) - tol && std::get<0>(arg) < std::get<1>(arg) + tol) ; - } - - - /// @brief Blaze matrix approx equality predicate - template - inline AssertionResult approxEqual(blaze::Matrix const& lhs, blaze::Matrix const& rhs, Real abs_tol, Real rel_tol = 0) - { - size_t const M = rows(lhs); - size_t const N = columns(lhs); - - if (rows(rhs) != M || columns(rhs) != N) - return AssertionFailure() << "Matrix size mismatch"; - - for (size_t i = 0; i < M; ++i) - for (size_t j = 0; j < N; ++j) - { - auto const a = (*lhs)(i, j); - auto const b = (*rhs)(i, j); - auto delta = a - b; - - if (std::isnan(a) != std::isnan(b) - || std::abs(delta) > abs_tol + rel_tol * std::abs(b)) - return AssertionFailure() - << "Actual value:\n" << lhs - << "Expected value:\n" << rhs - << "First mismatch at index (" << i << ", " << j << ")"; - } - - return AssertionSuccess(); - } - - - /// @brief Blaze vector approx equality predicate - template - inline std::enable_if_t, AssertionResult> - approxEqual(blaze::Vector const& lhs, blaze::Vector const& rhs, Real abs_tol, Real rel_tol = 0) - { - size_t const N = size(lhs); - - if (size(rhs) != N) - return AssertionFailure() << "Vector size mismatch"; - - for (size_t j = 0; j < N; ++j) - if (abs((*lhs)[j] - (*rhs)[j]) > abs_tol + rel_tol * abs((*rhs)[j])) - return AssertionFailure() - << "Actual value:\n" << lhs - << "Expected value:\n" << rhs - << "First mismatch at index (" << j << ")"; - - return AssertionSuccess(); - } - - - /// @brief Vector approx equality predicate with absolute tolerances specified for each element. - template - inline AssertionResult approxEqual(blaze::Vector const& lhs, blaze::Vector const& rhs, std::initializer_list abs_tol) - { - size_t const N = size(abs_tol); - - if (size(lhs) != N || size(rhs) != N) - return AssertionFailure() << "Vector size mismatch"; - - auto atol = begin(abs_tol); - - for (size_t j = 0; j < N; ++j, ++atol) - if (abs((*lhs)[j] - (*rhs)[j]) > *atol) - return AssertionFailure() << "First element mismatch at index " - << j << ", lhs=" << (*lhs)[j] << ", rhs=" << (*rhs)[j] << ", abs_tol=" << *atol; - - return AssertionSuccess(); - } - - - /// @brief Vector approx equality predicate with absolute tolerances specified for each element. - template - inline AssertionResult approxEqual(blaze::Vector const& lhs, blaze::Vector const& rhs, blaze::Vector const& abs_tol) - { - size_t const N = size(abs_tol); - - if (size(lhs) != N || size(rhs) != N) - return AssertionFailure() << "Vector size mismatch"; - - for (size_t j = 0; j < N; ++j) - if (abs((*lhs)[j] - (*rhs)[j]) > (*abs_tol)[j]) - return AssertionFailure() << "First element mismatch at index " - << j << ", lhs=" << (*lhs)[j] << ", rhs=" << (*rhs)[j] << ", abs_tol=" << (*abs_tol)[j]; - - return AssertionSuccess(); - } - - - /// @brief Scalar type approx equality predicate with specified tolerances. - /// - template - requires std::is_floating_point_v - inline AssertionResult approxEqual(Scalar actual, Scalar expected, Scalar abs_tol, Scalar rel_tol) - { - if (std::abs(actual - expected) > abs_tol + rel_tol * std::abs(expected)) - return AssertionFailure() - << "Floating point values differ more than by the specified tolerance." << std::endl - << "Actual: " << actual << ", expected: " << expected; + using namespace ::testing; + + + namespace detail + { + template + class ForcePrintImpl + : public T + { + friend void PrintTo(const ForcePrintImpl &m, ::std::ostream *o) + { + *o << "\n" << m; + } + }; + } + + + /* + * Makes the Eigen3 matrix classes printable from GTest checking macros like EXPECT_EQ. + * Usage: EXPECT_EQ(forcePrint(a), forcePrint(b)) + * Taken from this post: http://stackoverflow.com/questions/25146997/teach-google-test-how-to-print-eigen-matrix + */ + template + decltype(auto) forcePrint(T const& val) + { + return static_cast const&>(val); + } + + + MATCHER_P(FloatNearPointwise, tol, "Out of range") + { + return (std::get<0>(arg) > std::get<1>(arg) - tol && std::get<0>(arg) < std::get<1>(arg) + tol) ; + } + + + /// @brief Matrix approx equality predicate + template + inline AssertionResult approxEqual(MT1 const& lhs, MT2 const& rhs, Real abs_tol, Real rel_tol = 0) + { + size_t const M = rows(lhs); + size_t const N = columns(lhs); + + if (rows(rhs) != M || columns(rhs) != N) + return AssertionFailure() << "Matrix size mismatch"; + + for (size_t i = 0; i < M; ++i) + for (size_t j = 0; j < N; ++j) + { + auto const a = lhs(i, j); + auto const b = rhs(i, j); + auto delta = a - b; + + if (std::isnan(a) != std::isnan(b) + || std::abs(delta) > abs_tol + rel_tol * std::abs(b)) + return AssertionFailure() + << "Actual value:\n" << lhs + << "Expected value:\n" << rhs + << "First mismatch at index (" << i << ", " << j << ")"; + } + + return AssertionSuccess(); + } + + + /// @brief Blaze vector approx equality predicate + template + inline std::enable_if_t, AssertionResult> + approxEqual(blaze::Vector const& lhs, blaze::Vector const& rhs, Real abs_tol, Real rel_tol = 0) + { + size_t const N = size(lhs); + + if (size(rhs) != N) + return AssertionFailure() << "Vector size mismatch"; + + for (size_t j = 0; j < N; ++j) + if (abs((*lhs)[j] - (*rhs)[j]) > abs_tol + rel_tol * abs((*rhs)[j])) + return AssertionFailure() + << "Actual value:\n" << lhs + << "Expected value:\n" << rhs + << "First mismatch at index (" << j << ")"; + + return AssertionSuccess(); + } + + + /// @brief Vector approx equality predicate with absolute tolerances specified for each element. + template + inline AssertionResult approxEqual(blaze::Vector const& lhs, blaze::Vector const& rhs, std::initializer_list abs_tol) + { + size_t const N = size(abs_tol); + + if (size(lhs) != N || size(rhs) != N) + return AssertionFailure() << "Vector size mismatch"; + + auto atol = begin(abs_tol); + + for (size_t j = 0; j < N; ++j, ++atol) + if (abs((*lhs)[j] - (*rhs)[j]) > *atol) + return AssertionFailure() << "First element mismatch at index " + << j << ", lhs=" << (*lhs)[j] << ", rhs=" << (*rhs)[j] << ", abs_tol=" << *atol; + + return AssertionSuccess(); + } + + + /// @brief Vector approx equality predicate with absolute tolerances specified for each element. + template + inline AssertionResult approxEqual(blaze::Vector const& lhs, blaze::Vector const& rhs, blaze::Vector const& abs_tol) + { + size_t const N = size(abs_tol); + + if (size(lhs) != N || size(rhs) != N) + return AssertionFailure() << "Vector size mismatch"; + + for (size_t j = 0; j < N; ++j) + if (abs((*lhs)[j] - (*rhs)[j]) > (*abs_tol)[j]) + return AssertionFailure() << "First element mismatch at index " + << j << ", lhs=" << (*lhs)[j] << ", rhs=" << (*rhs)[j] << ", abs_tol=" << (*abs_tol)[j]; + + return AssertionSuccess(); + } + + + /// @brief Scalar type approx equality predicate with specified tolerances. + /// + template + requires std::is_floating_point_v + inline AssertionResult approxEqual(Scalar actual, Scalar expected, Scalar abs_tol, Scalar rel_tol) + { + if (std::abs(actual - expected) > abs_tol + rel_tol * std::abs(expected)) + return AssertionFailure() + << "Floating point values differ more than by the specified tolerance." << std::endl + << "Actual: " << actual << ", expected: " << expected; - return AssertionSuccess(); - } - - - /// @brief Exact equality comparison for matrices - template - inline AssertionResult exactEqual(blaze::Matrix const& lhs, blaze::Matrix const& rhs) - { - size_t const M = rows(lhs); - size_t const N = columns(lhs); + return AssertionSuccess(); + } + + + /// @brief Exact equality comparison for matrices + template + inline AssertionResult exactEqual(blaze::Matrix const& lhs, blaze::Matrix const& rhs) + { + size_t const M = rows(lhs); + size_t const N = columns(lhs); - if (rows(rhs) != M || columns(rhs) != N) - return AssertionFailure() << "Matrix size mismatch"; + if (rows(rhs) != M || columns(rhs) != N) + return AssertionFailure() << "Matrix size mismatch"; - for (size_t i = 0; i < M; ++i) - for (size_t j = 0; j < N; ++j) - if (!((*lhs)(i, j) == (*rhs)(i, j))) - return AssertionFailure() << "First element mismatch at index (" - << i << "," << j << "), lhs=" << (*lhs)(i, j) << ", rhs=" << (*rhs)(i, j); + for (size_t i = 0; i < M; ++i) + for (size_t j = 0; j < N; ++j) + if (!((*lhs)(i, j) == (*rhs)(i, j))) + return AssertionFailure() << "First element mismatch at index (" + << i << "," << j << "), lhs=" << (*lhs)(i, j) << ", rhs=" << (*rhs)(i, j); - return AssertionSuccess(); - } + return AssertionSuccess(); + } - /// @brief Exact equality comparison for vectors - template - inline AssertionResult exactEqual(blaze::Vector const& lhs, blaze::Vector const& rhs) - { - size_t const N = size(lhs); + /// @brief Exact equality comparison for vectors + template + inline AssertionResult exactEqual(blaze::Vector const& lhs, blaze::Vector const& rhs) + { + size_t const N = size(lhs); - if (size(rhs) != N) - return AssertionFailure() << "Vector size mismatch"; + if (size(rhs) != N) + return AssertionFailure() << "Vector size mismatch"; - for (size_t j = 0; j < N; ++j) - if (!((*lhs)[j] == (*rhs)[j])) - return AssertionFailure() << "First element mismatch at index " - << j << ", lhs=" << (*lhs)[j] << ", rhs=" << (*rhs)[j]; + for (size_t j = 0; j < N; ++j) + if (!((*lhs)[j] == (*rhs)[j])) + return AssertionFailure() << "First element mismatch at index " + << j << ", lhs=" << (*lhs)[j] << ", rhs=" << (*rhs)[j]; - return AssertionSuccess(); - } + return AssertionSuccess(); + } } #define BLAST_EXPECT_APPROX_EQ(val, expected, abs_tol, rel_tol) \ - EXPECT_TRUE(::blast::testing::approxEqual(val, expected, abs_tol, rel_tol)) + EXPECT_TRUE(::blast::testing::approxEqual(val, expected, abs_tol, rel_tol)) #define BLAST_ASSERT_APPROX_EQ(val, expected, abs_tol, rel_tol) \ - ASSERT_TRUE(::blast::testing::approxEqual(val, expected, abs_tol, rel_tol)) + ASSERT_TRUE(::blast::testing::approxEqual(val, expected, abs_tol, rel_tol)) #define BLAST_EXPECT_EQ(val, expected) \ - EXPECT_EQ(::blast::testing::forcePrint(val), ::blast::testing::forcePrint(expected)) + EXPECT_EQ(::blast::testing::forcePrint(val), ::blast::testing::forcePrint(expected)) #define BLAST_ASSERT_EQ(val, expected) \ - ASSERT_EQ(::blast::testing::forcePrint(val), ::blast::testing::forcePrint(expected)) + ASSERT_EQ(::blast::testing::forcePrint(val), ::blast::testing::forcePrint(expected)) diff --git a/test/blast/math/dense/GemmTest.cpp b/test/blast/math/dense/GemmTest.cpp index d56daaf5..d0310ebb 100644 --- a/test/blast/math/dense/GemmTest.cpp +++ b/test/blast/math/dense/GemmTest.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include diff --git a/test/blast/math/dense/GerTest.cpp b/test/blast/math/dense/GerTest.cpp index cbf84913..c208ea88 100644 --- a/test/blast/math/dense/GerTest.cpp +++ b/test/blast/math/dense/GerTest.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include namespace blast :: testing { diff --git a/test/blast/math/dense/Getf2Test.cpp b/test/blast/math/dense/Getf2Test.cpp index 9f725701..87e2486e 100644 --- a/test/blast/math/dense/Getf2Test.cpp +++ b/test/blast/math/dense/Getf2Test.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/test/blast/math/dense/GetrfTest.cpp b/test/blast/math/dense/GetrfTest.cpp index 59eaa7cb..e72ccf5f 100644 --- a/test/blast/math/dense/GetrfTest.cpp +++ b/test/blast/math/dense/GetrfTest.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/test/blast/math/dense/Iamax.cpp b/test/blast/math/dense/Iamax.cpp index c66134e1..869bfb84 100644 --- a/test/blast/math/dense/Iamax.cpp +++ b/test/blast/math/dense/Iamax.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include namespace blast :: testing diff --git a/test/blast/math/dense/PotrfTest.cpp b/test/blast/math/dense/PotrfTest.cpp index f8fa24d4..2e2936ce 100644 --- a/test/blast/math/dense/PotrfTest.cpp +++ b/test/blast/math/dense/PotrfTest.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/test/blast/math/dense/SyrkTest.cpp b/test/blast/math/dense/SyrkTest.cpp index 897b4d34..d706744a 100644 --- a/test/blast/math/dense/SyrkTest.cpp +++ b/test/blast/math/dense/SyrkTest.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include diff --git a/test/blast/math/dense/TrmmTest.cpp b/test/blast/math/dense/TrmmTest.cpp index 04005df3..b7c96073 100644 --- a/test/blast/math/dense/TrmmTest.cpp +++ b/test/blast/math/dense/TrmmTest.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace blast :: testing { diff --git a/test/blast/math/expressions/AssignDensePanelTest.cpp b/test/blast/math/expressions/AssignDensePanelTest.cpp index 593c7d34..0bfeaa60 100644 --- a/test/blast/math/expressions/AssignDensePanelTest.cpp +++ b/test/blast/math/expressions/AssignDensePanelTest.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace blast :: testing @@ -67,4 +67,4 @@ namespace blast :: testing { this->template testImpl(); } -} \ No newline at end of file +} diff --git a/test/blast/math/expressions/AssignPanelDenseTest.cpp b/test/blast/math/expressions/AssignPanelDenseTest.cpp index d13d6901..273673b4 100644 --- a/test/blast/math/expressions/AssignPanelDenseTest.cpp +++ b/test/blast/math/expressions/AssignPanelDenseTest.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace blast :: testing @@ -67,4 +67,4 @@ namespace blast :: testing { this->template testImpl(); } -} \ No newline at end of file +} diff --git a/test/blast/math/expressions/PMatTransExprTest.cpp b/test/blast/math/expressions/PMatTransExprTest.cpp index bd850f35..9716d78b 100644 --- a/test/blast/math/expressions/PMatTransExprTest.cpp +++ b/test/blast/math/expressions/PMatTransExprTest.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include namespace blast :: testing diff --git a/test/blast/math/panel/DynamicPanelMatrixTest.cpp b/test/blast/math/panel/DynamicPanelMatrixTest.cpp index 03ad02e2..6590d408 100644 --- a/test/blast/math/panel/DynamicPanelMatrixTest.cpp +++ b/test/blast/math/panel/DynamicPanelMatrixTest.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace blast :: testing @@ -112,4 +112,4 @@ namespace blast :: testing for (size_t j = 0; j < N; ++j) EXPECT_EQ(A(i, j), A1(i, j)) << "element mismatch at (" << i << ", " << j << ")"; } -} \ No newline at end of file +} diff --git a/test/blast/math/panel/GemmTest.cpp b/test/blast/math/panel/GemmTest.cpp index 71e88bd1..7d9be8d3 100644 --- a/test/blast/math/panel/GemmTest.cpp +++ b/test/blast/math/panel/GemmTest.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include diff --git a/test/blast/math/panel/PotrfTest.cpp b/test/blast/math/panel/PotrfTest.cpp index 46502097..0c011180 100644 --- a/test/blast/math/panel/PotrfTest.cpp +++ b/test/blast/math/panel/PotrfTest.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include namespace blast :: testing diff --git a/test/blast/math/panel/StaticPanelMatrixTest.cpp b/test/blast/math/panel/StaticPanelMatrixTest.cpp index 486b61c8..248f0e96 100644 --- a/test/blast/math/panel/StaticPanelMatrixTest.cpp +++ b/test/blast/math/panel/StaticPanelMatrixTest.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include namespace blast :: testing diff --git a/test/blast/math/simd/DynamicRegisterMatrixTest.cpp b/test/blast/math/simd/DynamicRegisterMatrixTest.cpp index 45908e9b..e8de88d5 100644 --- a/test/blast/math/simd/DynamicRegisterMatrixTest.cpp +++ b/test/blast/math/simd/DynamicRegisterMatrixTest.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include diff --git a/test/blast/math/simd/RegisterMatrixTest.cpp b/test/blast/math/simd/RegisterMatrixTest.cpp index 767c24b9..ab1ef32b 100644 --- a/test/blast/math/simd/RegisterMatrixTest.cpp +++ b/test/blast/math/simd/RegisterMatrixTest.cpp @@ -5,12 +5,16 @@ #include #include #include -#include +#include #include -#include +#include +#include +#include +#include +#include +#include #include -#include #include @@ -179,7 +183,7 @@ namespace blast :: testing using ET = ElementType_t; StaticMatrix A, B(0.); - blast::randomize(A); + randomize(A); RM ker; ker.load(1., ptr(A, 0, 0)); @@ -276,7 +280,7 @@ namespace blast :: testing randomize(A_ref); StaticPanelMatrix A, B; - A = A_ref; + assign(A, A_ref); RM ker; ker.load(ptr(A)); @@ -330,30 +334,21 @@ namespace blast :: testing using Traits = RegisterMatrixTraits; using ET = ElementType_t; - blaze::DynamicMatrix ma(Traits::rows, 1); - blaze::DynamicMatrix mb(Traits::columns, 1); - blaze::StaticMatrix mc, md; - - randomize(ma); - randomize(mb); - randomize(mc); - StaticPanelMatrix A; StaticPanelMatrix B; - StaticPanelMatrix C, D; + StaticPanelMatrix C; - A = ma; - B = mb; - C = mc; + randomize(A); + randomize(B); + randomize(C); TypeParam ker; ker.load(ptr(C)); ker.ger(column(ptr(A)), row(ptr(B).trans())); - ker.store(ptr(D)); - md = D; + reference::ger(rows(C), columns(C), 1., column(ptr(A)), column(ptr(B)).trans(), ptr(C), ptr(C)); - BLAST_EXPECT_EQ(md, evaluate(mc + ma * trans(mb))); + BLAST_EXPECT_EQ(ker, C); } @@ -377,7 +372,7 @@ namespace blast :: testing ker.load(1., ptr(C)); ker.ger(alpha, ptr(a), ptr(b)); - reference::ger(rows(C), columns(C), alpha, ptr(a), ptr(b), ptr(C)); + reference::ger(rows(C), columns(C), alpha, ptr(a), ptr(b), ptr(C), ptr(C)); BLAST_EXPECT_APPROX_EQ(ker, C, absTol(), relTol()); } @@ -389,23 +384,16 @@ namespace blast :: testing using Traits = RegisterMatrixTraits; using ET = ElementType_t; - DynamicMatrix ma(Traits::rows, 1); - DynamicMatrix mb(Traits::columns, 1); - StaticMatrix mc; - - randomize(ma); - randomize(mb); - randomize(mc); - - StaticMatrix const D_ref = ma * trans(mb) + mc; - StaticPanelMatrix A; StaticPanelMatrix B; StaticPanelMatrix C; - A = ma; - B = mb; - C = mc; + randomize(A); + randomize(B); + randomize(C); + + StaticMatrix D; + reference::ger(Traits::rows, Traits::columns, 1., column(ptr(A)), column(ptr(B)).trans(), ptr(C), ptr(D)); for (size_t m = 0; m <= rows(C); ++m) { @@ -417,7 +405,7 @@ namespace blast :: testing for (size_t i = 0; i < m; ++i) for (size_t j = 0; j < n; ++j) - ASSERT_EQ(ker(i, j), i < m && j < n ? D_ref(i, j) : 0.) << "element mismatch at (" << i << ", " << j << "), " + ASSERT_EQ(ker(i, j), i < m && j < n ? D(i, j) : 0.) << "element mismatch at (" << i << ", " << j << "), " << "store size = " << m << "x" << n; } } @@ -438,7 +426,8 @@ namespace blast :: testing randomize(b); randomize(C); - StaticMatrix const D_ref = a * trans(b) + C; + StaticMatrix D; + reference::ger(Traits::rows, Traits::columns, 1., ptr(a), ptr(trans(b)), ptr(C), ptr(D)); for (size_t m = 0; m <= rows(C); ++m) { @@ -450,7 +439,7 @@ namespace blast :: testing for (size_t i = 0; i < m; ++i) for (size_t j = 0; j < n; ++j) - BLAST_ASSERT_APPROX_EQ(ker(i, j), D_ref(i, j), absTol(), relTol()) + BLAST_ASSERT_APPROX_EQ(ker(i, j), D(i, j), absTol(), relTol()) << "element mismatch at (" << i << ", " << j << "), " << "store size = " << m << "x" << n; } @@ -477,7 +466,9 @@ namespace blast :: testing ker.ger(ET(1.), ptr(a), ptr(trans(b))); ker.store(ptr(D)); - BLAST_EXPECT_EQ(D, evaluate(C + a * trans(b))); + StaticMatrix D_ref; + reference::ger(Traits::rows, Traits::columns, 1., ptr(a), ptr(trans(b)), ptr(C), ptr(D_ref)); + BLAST_EXPECT_EQ(D, D_ref); } @@ -491,21 +482,18 @@ namespace blast :: testing if constexpr (m >= n) { StaticMatrix A, L; - - { - StaticMatrix C0; - makePositiveDefinite(C0); - - submatrix(A, 0, 0, n, n) = C0; - randomize(submatrix(A, n, 0, m - n, n)); - } + makePositiveDefinite(submatrix(A, 0, 0, n, n)); + randomize(submatrix(A, n, 0, m - n, n)); TypeParam ker; ker.load(ptr(A)); ker.potrf(); ker.store(ptr(L)); - BLAST_ASSERT_APPROX_EQ(submatrix(L * trans(L), 0, 0, m, n), A, absTol(), relTol()); + StaticMatrix LTL {}; + reference::gemm(1., L, trans(L), 0., LTL, LTL); + + BLAST_ASSERT_APPROX_EQ(submatrix(LTL, 0, 0, m, n), A, absTol(), relTol()); } else { @@ -535,18 +523,18 @@ namespace blast :: testing L(i, j) += ET(1.); // Improve conditioning } else - reset(L(i, j)); + L(i, j) = ET(0.); randomize(B); - StaticMatrix LL; - StaticMatrix BB, XX; + blaze::StaticMatrix LL; + blaze::StaticMatrix BB, XX; LL = L; BB = B; // True value - XX = evaluate(BB * inv(trans(LL))); + XX = evaluate(BB * inv(blaze::trans(LL))); ker.load(ptr(B)); ker.trsm(Side::Right, UpLo::Upper, ptr(L).trans()); @@ -565,8 +553,8 @@ namespace blast :: testing RM ker; using blaze::randomize; - StaticMatrix L; - StaticMatrix B, B1; + blaze::StaticMatrix L; + blaze::StaticMatrix B, B1; for (size_t i = 0; i < RM::columns(); ++i) for (size_t j = 0; j < RM::columns(); ++j) @@ -577,7 +565,7 @@ namespace blast :: testing L(i, j) += ET(1.); // Improve conditioning } else - reset(L(i, j)); + blaze::reset(L(i, j)); randomize(B); @@ -585,7 +573,7 @@ namespace blast :: testing ker.trsm(Side::Right, UpLo::Upper, trans(ptr(L))); // TODO: should be strictly equal? - BLAST_ASSERT_APPROX_EQ(ker, evaluate(B * inv(trans(L))), absTol(), relTol()); + BLAST_ASSERT_APPROX_EQ(ker, evaluate(B * inv(blaze::trans(L))), absTol(), relTol()); } @@ -594,12 +582,11 @@ namespace blast :: testing using RM = TypeParam; using ET = ElementType_t; + blaze::DynamicMatrix A(RM::rows(), RM::rows()); + blaze::DynamicMatrix B(RM::rows(), RM::columns()); - DynamicMatrix A(RM::rows(), RM::rows()); - DynamicMatrix B(RM::rows(), RM::columns()); - - randomize(A); - randomize(B); + blaze::randomize(A); + blaze::randomize(B); ET alpha {}; blaze::randomize(alpha); @@ -610,7 +597,7 @@ namespace blast :: testing // Reset lower-triangular part for (size_t i = 0; i < A.rows(); ++i) for (size_t j = 0; j < i && j < A.columns(); ++j) - reset(A(i, j)); + blaze::reset(A(i, j)); // TODO: should be strictly equal? BLAST_ASSERT_APPROX_EQ(ker, alpha * A * B, absTol(), relTol()); @@ -622,12 +609,11 @@ namespace blast :: testing using RM = TypeParam; using ET = ElementType_t; + blaze::DynamicMatrix A(RM::columns(), RM::columns()); + blaze::DynamicMatrix B(RM::rows(), RM::columns()); - DynamicMatrix A(RM::columns(), RM::columns()); - DynamicMatrix B(RM::rows(), RM::columns()); - - randomize(A); - randomize(B); + blaze::randomize(A); + blaze::randomize(B); ET alpha {}; blaze::randomize(alpha); @@ -638,7 +624,7 @@ namespace blast :: testing // Reset upper-triangular part for (size_t i = 0; i < A.rows(); ++i) for (size_t j = i + 1; j < A.columns(); ++j) - reset(A(i, j)); + blaze::reset(A(i, j)); // TODO: should be strictly equal? BLAST_ASSERT_APPROX_EQ(ker, alpha * B * A, absTol(), relTol()); diff --git a/test/blast/math/simd/SimdVecTest.cpp b/test/blast/math/simd/SimdVecTest.cpp index 9d9e48ad..45bd03f9 100644 --- a/test/blast/math/simd/SimdVecTest.cpp +++ b/test/blast/math/simd/SimdVecTest.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/test/blast/math/views/RowTest.cpp b/test/blast/math/views/RowTest.cpp index 6d89e907..17cfced6 100644 --- a/test/blast/math/views/RowTest.cpp +++ b/test/blast/math/views/RowTest.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include namespace blast :: testing @@ -61,4 +61,4 @@ namespace blast :: testing } } } -} \ No newline at end of file +} diff --git a/test/blast/math/views/SubmatrixTest.cpp b/test/blast/math/views/SubmatrixTest.cpp index 801537ed..6e35e529 100644 --- a/test/blast/math/views/SubmatrixTest.cpp +++ b/test/blast/math/views/SubmatrixTest.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace blast :: testing @@ -79,4 +79,4 @@ namespace blast :: testing EXPECT_EQ(IsAligned_v, false); } -} \ No newline at end of file +}