From 92abe5c7cd6d71b4281a603357a7b7b19e68e93f Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 10:42:37 +0800 Subject: [PATCH 01/15] MSVC: Work around a possible compiler issue --- include/experimental/__p1673_bits/transposed.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/experimental/__p1673_bits/transposed.hpp b/include/experimental/__p1673_bits/transposed.hpp index f65cdeae..45ab706f 100644 --- a/include/experimental/__p1673_bits/transposed.hpp +++ b/include/experimental/__p1673_bits/transposed.hpp @@ -252,7 +252,10 @@ namespace impl { template static auto mapping(const typename layout_stride::template mapping& orig_map) { using original_mapping_type = typename layout_stride::template mapping; - using extents_type = transpose_extents_t; + using original_extents_type = typename original_mapping_type::extents_type; + using extents_type = transpose_extents_t; + // Visual Studio 2022 emits a build error with the commented-out line below. + //using extents_type = transpose_extents_t; using return_mapping_type = typename layout_type::template mapping; // NOTE (mfh 2022/07/04) Commented-out code relates // to the build error reported in my comment here: From e423fba7a4726b79e440f230b38bc6a163ae94a9 Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 11:53:15 +0800 Subject: [PATCH 02/15] accessor_scaled: Remove proxy reference accessor_scaled::access now returns element_type, not a proxy reference type. The product is thus evaluated immediately on access. --- include/experimental/__p1673_bits/scaled.hpp | 30 ++++++++++---------- tests/native/scaled.cpp | 4 +-- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/include/experimental/__p1673_bits/scaled.hpp b/include/experimental/__p1673_bits/scaled.hpp index 1a7d9bc7..3b4d185e 100644 --- a/include/experimental/__p1673_bits/scaled.hpp +++ b/include/experimental/__p1673_bits/scaled.hpp @@ -53,32 +53,32 @@ namespace linalg { template class accessor_scaled { public: - using reference = - scaled_scalar>; - using element_type = std::add_const_t; + using element_type = decltype(std::declval() * std::declval()); + using reference = element_type; using data_handle_type = typename Accessor::data_handle_type; using offset_policy = accessor_scaled; - accessor_scaled(ScalingFactor scaling_factor, Accessor accessor) : - scaling_factor_(std::move(scaling_factor)), accessor_(accessor) + accessor_scaled(const ScalingFactor& scaling_factor, const Accessor& accessor) : + scaling_factor_(scaling_factor), + accessor_(accessor) {} MDSPAN_TEMPLATE_REQUIRES( - class OtherElementType, - /* requires */ (std::is_convertible_v< - typename default_accessor::element_type(*)[], - typename Accessor::element_type(*)[] - >) + class OtherScalingFactor, + class OtherNestedAccessor, + /* requires */ ( + std::is_constructible_v && + std::is_constructible_v + ) ) - accessor_scaled(ScalingFactor scaling_factor, - default_accessor accessor) : - scaling_factor_(std::move(scaling_factor)), accessor_(accessor) + accessor_scaled(const accessor_scaled& other) : + scaling_factor_(other.scaling_factor()), + accessor_(other.nested_accessor()) {} reference access(data_handle_type p, ::std::size_t i) const noexcept { - return reference(scaling_factor_, accessor_.access(p, i)); + return scaling_factor_ * typename Accessor::element_type(accessor_.access(p, i)); } typename offset_policy::data_handle_type diff --git a/tests/native/scaled.cpp b/tests/native/scaled.cpp index 479befb9..5c3daba1 100644 --- a/tests/native/scaled.cpp +++ b/tests/native/scaled.cpp @@ -90,7 +90,7 @@ namespace { scaled_accessor_t accessor0{scalingFactor, y.accessor()}; } - auto y_scaled = scaled (scalingFactor, y); + auto y_scaled = scaled(scalingFactor, y); for (std::size_t k = 0; k < vectorSize; ++k) { const vector_element_type x_k = vector_element_type(k) + 1.0; EXPECT_EQ( x(k), x_k ); @@ -106,8 +106,6 @@ namespace { // Don't ever capture an expression template type by auto in // real code. I'm just testing whether some operators work. auto y_scaled_ref = y_scaled(k); - using ref_t = decltype(y_scaled_ref); - static_assert(! std::is_same_v); using type1 = decltype(y_scaled_ref + float(1.0)); static_assert(std::is_same_v); From 905757a5453b1a0f7db493fcc89cd2c1c233618d Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 11:59:55 +0800 Subject: [PATCH 03/15] Rename accessor_scaled -> scaled_accessor --- .../__p1673_bits/blas3_matrix_product.hpp | 16 ++++++------- include/experimental/__p1673_bits/scaled.hpp | 14 +++++------ tests/native/scaled.cpp | 24 +++++++++---------- .../kokkos-kernels/blas2_gemv_kk.hpp | 2 +- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/include/experimental/__p1673_bits/blas3_matrix_product.hpp b/include/experimental/__p1673_bits/blas3_matrix_product.hpp index 3ae195aa..5bea5e4e 100644 --- a/include/experimental/__p1673_bits/blas3_matrix_product.hpp +++ b/include/experimental/__p1673_bits/blas3_matrix_product.hpp @@ -191,8 +191,8 @@ constexpr bool valid_input_blas_accessor() using def_acc_type = default_accessor; using conj_def_acc_type = accessor_conjugate; - using scal_def_acc_type = accessor_scaled; - using scal_conj_acc_type = accessor_scaled; + using scal_def_acc_type = scaled_accessor; + using scal_conj_acc_type = scaled_accessor; using conj_scal_acc_type = accessor_conjugate; // The two matrices' accessor types need not be the same. @@ -288,12 +288,12 @@ matrix_product_dispatch_to_blas() } template -static constexpr bool is_compatible_accessor_scaled_v = false; +static constexpr bool is_compatible_scaled_accessor_v = false; template -static constexpr bool is_compatible_accessor_scaled_v< - accessor_scaled, ValueType> = - std::is_same_v::value_type, ValueType>; +static constexpr bool is_compatible_scaled_accessor_v< + scaled_accessor, ValueType> = + std::is_same_v::value_type, ValueType>; template static constexpr bool is_accessor_conjugate_v = false; @@ -309,12 +309,12 @@ extractScalingFactor(in_matrix_t A, using acc_t = typename in_matrix_t::accessor_type; using val_t = typename in_matrix_t::value_type; - if constexpr (is_compatible_accessor_scaled_v) { + if constexpr (is_compatible_scaled_accessor_v) { return A.accessor.scale_factor(); } else if constexpr (is_accessor_conjugate_v) { // conjugated(scaled(alpha, A)) means that both alpha and A are conjugated. using nested_acc_t = decltype(A.accessor().nested_accessor()); - if constexpr (is_compatible_accessor_scaled_v) { + if constexpr (is_compatible_scaled_accessor_v) { return impl::conj_if_needed(extractScalingFactor(A.accessor.nested_accessor())); } else { return defaultValue; diff --git a/include/experimental/__p1673_bits/scaled.hpp b/include/experimental/__p1673_bits/scaled.hpp index 3b4d185e..382b8992 100644 --- a/include/experimental/__p1673_bits/scaled.hpp +++ b/include/experimental/__p1673_bits/scaled.hpp @@ -51,15 +51,15 @@ inline namespace __p1673_version_0 { namespace linalg { template -class accessor_scaled { +class scaled_accessor { public: using element_type = decltype(std::declval() * std::declval()); using reference = element_type; using data_handle_type = typename Accessor::data_handle_type; using offset_policy = - accessor_scaled; + scaled_accessor; - accessor_scaled(const ScalingFactor& scaling_factor, const Accessor& accessor) : + scaled_accessor(const ScalingFactor& scaling_factor, const Accessor& accessor) : scaling_factor_(scaling_factor), accessor_(accessor) {} @@ -72,7 +72,7 @@ class accessor_scaled { std::is_constructible_v ) ) - accessor_scaled(const accessor_scaled& other) : + scaled_accessor(const scaled_accessor& other) : scaling_factor_(other.scaling_factor()), accessor_(other.nested_accessor()) {} @@ -104,7 +104,7 @@ namespace impl { template using scaled_element_type = - std::add_const_t::element_type>; + std::add_const_t::element_type>; } // namespace impl @@ -116,11 +116,11 @@ template, Extents, Layout, - accessor_scaled> + scaled_accessor> scaled(ScalingFactor scaling_factor, mdspan x) { - using acc_type = accessor_scaled; + using acc_type = scaled_accessor; return {x.data_handle(), x.mapping(), acc_type{scaling_factor, x.accessor()}}; } diff --git a/tests/native/scaled.cpp b/tests/native/scaled.cpp index 5c3daba1..77c7dfc0 100644 --- a/tests/native/scaled.cpp +++ b/tests/native/scaled.cpp @@ -7,9 +7,9 @@ namespace { using std::experimental::linalg::scaled; template - void test_accessor_scaled_element_constification() + void test_scaled_accessor_element_constification() { - using std::experimental::linalg::accessor_scaled; + using std::experimental::linalg::scaled_accessor; using std::experimental::linalg::scaled_scalar; using nc_def_acc_type = default_accessor; @@ -18,8 +18,8 @@ namespace { nc_def_acc_type nc_acc; c_def_acc_type c_acc; - using as_nc_type = accessor_scaled; - using as_c_type = accessor_scaled; + using as_nc_type = scaled_accessor; + using as_c_type = scaled_accessor; ScalingFactor scal{}; as_nc_type acc_scal_nc(scal, nc_acc); as_c_type acc_scal_c0(scal, c_acc); @@ -28,12 +28,12 @@ namespace { as_c_type acc_scal_c1(scal, nc_acc); } - TEST(accessor_scaled, element_constification) + TEST(scaled_accessor, element_constification) { - test_accessor_scaled_element_constification(); - test_accessor_scaled_element_constification(); - test_accessor_scaled_element_constification, std::complex>(); - test_accessor_scaled_element_constification, std::complex>(); + test_scaled_accessor_element_constification(); + test_scaled_accessor_element_constification(); + test_scaled_accessor_element_constification, std::complex>(); + test_scaled_accessor_element_constification, std::complex>(); } // scaled(1 << 20, scaled(1 << 20, x)) with x having value_type double @@ -81,12 +81,12 @@ namespace { const scaling_factor_type scalingFactor (-3.0); - // Make sure that accessor_scaled compiles + // Make sure that scaled_accessor compiles { using accessor_t = vector_t::accessor_type; - using std::experimental::linalg::accessor_scaled; + using std::experimental::linalg::scaled_accessor; using scaled_accessor_t = - accessor_scaled; + scaled_accessor; scaled_accessor_t accessor0{scalingFactor, y.accessor()}; } diff --git a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_gemv_kk.hpp b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_gemv_kk.hpp index 9b4f845b..a862caa0 100644 --- a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_gemv_kk.hpp +++ b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_gemv_kk.hpp @@ -14,7 +14,7 @@ T get_scaling_factor(Accessor /*a*/, T /*v*/) { } template -auto get_scaling_factor(std::experimental::linalg::accessor_scaled a, +auto get_scaling_factor(std::experimental::linalg::scaled_accessor a, T /*v*/) { return T(a.scale_factor()); From 49dbbfcf59e1dc658b4e3595609229f72d0d569b Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 15:13:41 +0800 Subject: [PATCH 04/15] Implement LWG changes to conjugate_accessor * Rename accessor_conjugate to conjugate accessor * Don't use proxy reference machinery; instead, just make the "reference" a value * Add missing converting constructor --- .../__p1673_bits/blas3_matrix_product.hpp | 12 +-- .../experimental/__p1673_bits/conjugated.hpp | 80 +++++-------------- tests/native/conjugated.cpp | 34 ++++---- .../kokkos-kernels/blas1_dot_kk.hpp | 2 +- .../blas2_matrix_rank_1_update.hpp | 4 +- 5 files changed, 45 insertions(+), 87 deletions(-) diff --git a/include/experimental/__p1673_bits/blas3_matrix_product.hpp b/include/experimental/__p1673_bits/blas3_matrix_product.hpp index 5bea5e4e..b637070a 100644 --- a/include/experimental/__p1673_bits/blas3_matrix_product.hpp +++ b/include/experimental/__p1673_bits/blas3_matrix_product.hpp @@ -190,10 +190,10 @@ constexpr bool valid_input_blas_accessor() using acc_type = typename in_matrix_t::accessor_type; using def_acc_type = default_accessor; - using conj_def_acc_type = accessor_conjugate; + using conj_def_acc_type = conjugate_accessor; using scal_def_acc_type = scaled_accessor; using scal_conj_acc_type = scaled_accessor; - using conj_scal_acc_type = accessor_conjugate; + using conj_scal_acc_type = conjugate_accessor; // The two matrices' accessor types need not be the same. // Input matrices may be scaled or transposed. @@ -296,10 +296,10 @@ static constexpr bool is_compatible_scaled_accessor_v< std::is_same_v::value_type, ValueType>; template -static constexpr bool is_accessor_conjugate_v = false; +static constexpr bool is_conjugate_accessor_v = false; template -static constexpr bool is_accessor_conjugate_v> = true; +static constexpr bool is_conjugate_accessor_v> = true; template typename in_matrix_t::value_type @@ -311,7 +311,7 @@ extractScalingFactor(in_matrix_t A, if constexpr (is_compatible_scaled_accessor_v) { return A.accessor.scale_factor(); - } else if constexpr (is_accessor_conjugate_v) { + } else if constexpr (is_conjugate_accessor_v) { // conjugated(scaled(alpha, A)) means that both alpha and A are conjugated. using nested_acc_t = decltype(A.accessor().nested_accessor()); if constexpr (is_compatible_scaled_accessor_v) { @@ -344,7 +344,7 @@ constexpr bool extractConjImpl(Accessor a) using elt_t = typename Accessor::element_type; using def_acc_t = default_accessor; - using conj_def_acc_t = accessor_conjugate; + using conj_def_acc_t = conjugate_accessor; if constexpr (std::is_same_v) { return false; } else if constexpr (std::is_same_v) { diff --git a/include/experimental/__p1673_bits/conjugated.hpp b/include/experimental/__p1673_bits/conjugated.hpp index 1ad3e788..6bdfd672 100644 --- a/include/experimental/__p1673_bits/conjugated.hpp +++ b/include/experimental/__p1673_bits/conjugated.hpp @@ -51,74 +51,34 @@ inline namespace __p1673_version_0 { namespace linalg { template -class accessor_conjugate; - -namespace impl { - template< - class Accessor, - bool is_arith = - std::is_arithmetic_v< - std::remove_cv_t - > - > - struct accessor_conjugate_aliases {}; - - template - struct accessor_conjugate_aliases - { - using reference = typename Accessor::reference; - using element_type = - std::add_const_t; - using data_handle_type = typename Accessor::data_handle_type; - using offset_policy = typename Accessor::offset_policy; - }; - - template - struct accessor_conjugate_aliases - { - private: - using accessor_value_type = - std::remove_cv_t; - public: - using reference = - conjugated_scalar; - using element_type = - std::add_const_t; - using data_handle_type = typename Accessor::data_handle_type; - using offset_policy = - accessor_conjugate; - }; - -} // namespace impl - -template -class accessor_conjugate { +class conjugate_accessor { private: Accessor accessor_; - using aliases = impl::accessor_conjugate_aliases; public: - using reference = typename aliases::reference; - using element_type = typename aliases::element_type; - using data_handle_type = typename aliases::data_handle_type; - using offset_policy = typename aliases::offset_policy; + using element_type = decltype(impl::conj_if_needed(std::declval())); + using reference = element_type; + using data_handle_type = typename Accessor::data_handle_type; + using offset_policy = conjugate_accessor; - accessor_conjugate(Accessor accessor) : accessor_(accessor) {} + conjugate_accessor(const Accessor& accessor) : + accessor_(accessor) + {} MDSPAN_TEMPLATE_REQUIRES( - class OtherElementType, - /* requires */ (std::is_convertible_v< - typename default_accessor::element_type(*)[], - typename Accessor::element_type(*)[] - >) + class OtherNestedAccessor, + /* requires */ ( + std::is_constructible_v + ) ) - accessor_conjugate(default_accessor accessor) : accessor_(accessor) {} + conjugate_accessor(const conjugate_accessor& other) : + accessor_(other.nested_accessor()) + {} reference access(data_handle_type p, ::std::size_t i) const - noexcept(noexcept(reference(accessor_.access(p, i)))) + noexcept(noexcept(impl::conj_if_needed(typename Accessor::element_type(accessor_.access(p, i))))) { - return reference(accessor_.access(p, i)); + return impl::conj_if_needed(typename Accessor::element_type(accessor_.access(p, i))); } typename offset_policy::data_handle_type offset(data_handle_type p, ::std::size_t i) const @@ -138,8 +98,8 @@ auto conjugated(mdspan a) (a.data_handle(), a.mapping(), a.accessor()); } else { using return_element_type = - typename accessor_conjugate::element_type; - using return_accessor_type = accessor_conjugate; + typename conjugate_accessor::element_type; + using return_accessor_type = conjugate_accessor; return mdspan (a.data_handle(), a.mapping(), return_accessor_type(a.accessor())); } @@ -148,7 +108,7 @@ auto conjugated(mdspan a) // Conjugation is self-annihilating template auto conjugated( - mdspan> a) + mdspan> a) { using return_element_type = typename NestedAccessor::element_type; using return_accessor_type = NestedAccessor; diff --git a/tests/native/conjugated.cpp b/tests/native/conjugated.cpp index daaf4bf2..3ee0e078 100644 --- a/tests/native/conjugated.cpp +++ b/tests/native/conjugated.cpp @@ -6,9 +6,9 @@ namespace { using std::experimental::linalg::conjugated; template - void test_accessor_conjugate_element_constification() + void test_conjugate_accessor_element_constification() { - using std::experimental::linalg::accessor_conjugate; + using std::experimental::linalg::conjugate_accessor; using std::experimental::default_accessor; using std::experimental::linalg::conjugated_scalar; using value_type = std::remove_cv_t; @@ -19,19 +19,17 @@ namespace { nc_def_acc_type nc_acc; c_def_acc_type c_acc; - using aj_nc_type = accessor_conjugate; - using expected_nc_ref = - std::conditional_t>; + using aj_nc_type = conjugate_accessor; + using expected_nc_ref = value_type; // conjugate_accessor's reference type is its element_type static_assert(std::is_same_v); - using expected_nc_elt = std::add_const_t::value_type>>; + using expected_nc_elt = value_type; static_assert(std::is_same_v); static_assert(std::is_same_v); - using aj_c_type = accessor_conjugate; - using expected_c_ref = std::conditional_t>; + using aj_c_type = conjugate_accessor; + using expected_c_ref = value_type; // conjugate_accessor's reference type is its element_type static_assert(std::is_same_v); - using expected_c_elt = std::add_const_t::value_type>>; + using expected_c_elt = value_type; static_assert(std::is_same_v); static_assert(std::is_same_v); @@ -42,12 +40,12 @@ namespace { aj_c_type acc_conj_c1(nc_acc); } - TEST(accessor_conjugate, element_constification) + TEST(conjugate_accessor, element_constification) { - test_accessor_conjugate_element_constification(); - test_accessor_conjugate_element_constification(); - test_accessor_conjugate_element_constification>(); - test_accessor_conjugate_element_constification>(); + test_conjugate_accessor_element_constification(); + test_conjugate_accessor_element_constification(); + test_conjugate_accessor_element_constification>(); + test_conjugate_accessor_element_constification>(); } TEST(conjugated, mdspan_complex_double) @@ -70,11 +68,11 @@ namespace { y(k) = y_k; } - // Make sure that accessor_conjugate compiles + // Make sure that conjugate_accessor compiles { using accessor_t = vector_t::accessor_type; - using std::experimental::linalg::accessor_conjugate; - using accessor_conj_t = accessor_conjugate; + using std::experimental::linalg::conjugate_accessor; + using accessor_conj_t = conjugate_accessor; accessor_conj_t acc{y.accessor()}; } diff --git a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas1_dot_kk.hpp b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas1_dot_kk.hpp index 66914639..a619fa9e 100644 --- a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas1_dot_kk.hpp +++ b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas1_dot_kk.hpp @@ -80,7 +80,7 @@ Scalar dot(kokkos_exec, ElementType_x, std::experimental::extents, Layout_x, - std::experimental::linalg::accessor_conjugate< + std::experimental::linalg::conjugate_accessor< std::experimental::default_accessor, ElementType_x > > x, diff --git a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_matrix_rank_1_update.hpp b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_matrix_rank_1_update.hpp index 3390367a..9ed0a32c 100644 --- a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_matrix_rank_1_update.hpp +++ b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_matrix_rank_1_update.hpp @@ -1,4 +1,4 @@ - /* +/* //@HEADER // ************************************************************************ // @@ -120,7 +120,7 @@ void matrix_rank_1_update(kokkos_exec &&/* exec */, std::experimental::mdspan, Layout_x, std::experimental::default_accessor> x, std::experimental::mdspan, Layout_y, - std::experimental::linalg::accessor_conjugate< + std::experimental::linalg::conjugate_accessor< std::experimental::default_accessor, ElementType_y>> y, std::experimental::mdspan, Layout_A, std::experimental::default_accessor> A) From 9c41a6c43e3b99a2338bc19f1e7706b421a944c7 Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 16:21:00 +0800 Subject: [PATCH 05/15] Fix some MSVC build warnings --- examples/03_matrix_vector_product_mixedprec.cpp | 2 +- tests/native/proxy_refs.cpp | 2 +- tests/native/scaled.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/03_matrix_vector_product_mixedprec.cpp b/examples/03_matrix_vector_product_mixedprec.cpp index 2b1388f4..b02999f7 100644 --- a/examples/03_matrix_vector_product_mixedprec.cpp +++ b/examples/03_matrix_vector_product_mixedprec.cpp @@ -35,7 +35,7 @@ int main(int argc, char* argv[]) { for(int m=0; m(1000.0 * m + 100.0 * i + j); for(int i=0; i fncs(fn); EXPECT_EQ(fn, FakeRealNumber(fncs)); diff --git a/tests/native/scaled.cpp b/tests/native/scaled.cpp index 77c7dfc0..4257ea5c 100644 --- a/tests/native/scaled.cpp +++ b/tests/native/scaled.cpp @@ -139,7 +139,7 @@ namespace { vector_t x(storage.data(), vectorSize); for (std::size_t k = 0; k < vectorSize; ++k) { - const vector_element_type x_k = vector_element_type(k) + 1.0; + const vector_element_type x_k = vector_element_type(static_cast(k)) + 1.0; x(k) = x_k; } From 5a8722f88b99bbcffa45d9beada732046c082bbb Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 16:45:38 +0800 Subject: [PATCH 06/15] scaled_accessor: Make access conditionally noexcept --- include/experimental/__p1673_bits/scaled.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/experimental/__p1673_bits/scaled.hpp b/include/experimental/__p1673_bits/scaled.hpp index 382b8992..600fb5eb 100644 --- a/include/experimental/__p1673_bits/scaled.hpp +++ b/include/experimental/__p1673_bits/scaled.hpp @@ -77,7 +77,8 @@ class scaled_accessor { accessor_(other.nested_accessor()) {} - reference access(data_handle_type p, ::std::size_t i) const noexcept { + reference access(data_handle_type p, ::std::size_t i) const + noexcept(noexcept(scaling_factor_* typename Accessor::element_type(accessor_.access(p, i)))) { return scaling_factor_ * typename Accessor::element_type(accessor_.access(p, i)); } From 5df0d48598c11df9605a44b9ba32b359e6054749 Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 17:58:36 +0800 Subject: [PATCH 07/15] Factor out "fake" numbers for tests ...into their own reusable header file. Move conj_if_needed, real_part, and imag_part tests out of proxy_refs.cpp into a new test file. --- tests/native/CMakeLists.txt | 1 + tests/native/proxy_refs.cpp | 330 +---------------------------- tests/native/test_numbers.hpp | 228 ++++++++++++++++++++ tests/native/test_test_numbers.cpp | 223 +++++++++++++++++++ 4 files changed, 454 insertions(+), 328 deletions(-) create mode 100644 tests/native/test_numbers.hpp create mode 100644 tests/native/test_test_numbers.cpp diff --git a/tests/native/CMakeLists.txt b/tests/native/CMakeLists.txt index d8aa3c2e..c3782457 100644 --- a/tests/native/CMakeLists.txt +++ b/tests/native/CMakeLists.txt @@ -33,6 +33,7 @@ linalg_add_test(scale) linalg_add_test(scaled) linalg_add_test(swap) linalg_add_test(symm) +linalg_add_test(test_test_numbers) linalg_add_test(transposed) linalg_add_test(trmm) linalg_add_test(trsm) diff --git a/tests/native/proxy_refs.cpp b/tests/native/proxy_refs.cpp index 0d53a6ec..759b1917 100644 --- a/tests/native/proxy_refs.cpp +++ b/tests/native/proxy_refs.cpp @@ -1,182 +1,10 @@ -// To try using subscript operator comment in macro below -// the header will by default also check for the feature macro, and enable it -// defining the macro to 0 will overwrite the automatic setting -// x86-64 clang (experimental auto NSDMI) supports the operator, but you need -// to explicitly comment in below macro -//#define MDSPAN_USE_BRACKET_OPERATOR 1 - -// To force enable operator() comment in the macro below -// You can enable both at the same time. -//#define MDSPAN_USE_PAREN_OPERATOR 0 - +#define MDSPAN_USE_PAREN_OPERATOR 1 #define P1673_CONJUGATED_SCALAR_ARITHMETIC_OPERATORS_REFERENCE_OVERLOADS 1 #include "gtest/gtest.h" +#include "./test_numbers.hpp" #include -/////////////////////////////////////////////////////////// -// Custom real number type for tests -/////////////////////////////////////////////////////////// - -struct FakeRealNumber { - float value; - -#ifdef __cpp_impl_three_way_comparison - bool operator==(const FakeRealNumber&) const = default; -#else - friend bool operator==(const FakeRealNumber& x, const FakeRealNumber& y) - { - return x.value == y.value; - } -#endif -}; -// Non-arithmetic types need a definition of conj, -// else conjugated_scalar won't compile with them. -FakeRealNumber conj(const FakeRealNumber& x) { return x; } - -// Custom complex number type - -struct FakeComplex { - double real; - double imag; - -#ifdef __cpp_impl_three_way_comparison - bool operator==(const FakeComplex&) const = default; -#else - friend bool operator==(const FakeComplex& x, const FakeComplex& y) - { - return x.real == y.real && x.imag == y.imag; - } -#endif - - constexpr FakeComplex& operator+=(const FakeComplex& other) - { - real += other.real; - imag += other.imag; - return *this; - } - constexpr FakeComplex& operator-=(const FakeComplex& other) - { - real -= other.real; - imag -= other.imag; - return *this; - } - constexpr FakeComplex& operator*=(const FakeComplex& other) - { - real = real * other.real - imag * other.imag; - imag = imag * other.real + real * other.imag; - return *this; - } - constexpr FakeComplex& operator/=(const FakeComplex& other) - { - // just for illustration; please don't implement it this way. - const auto other_mag = other.real * other.real + other.imag * other.imag; - real = (real * other.real + imag * other.imag) / other_mag; - imag = (imag * other.real - real * other.imag) / other_mag; - return *this; - } - - constexpr FakeComplex& operator+=(const double other) - { - real += other; - return *this; - } - constexpr FakeComplex& operator-=(const double other) - { - real -= other; - return *this; - } - constexpr FakeComplex& operator*=(const double other) - { - real *= other; - imag *= other; - return *this; - } - constexpr FakeComplex& operator/=(const double other) - { - real /= other; - imag /= other; - return *this; - } -}; - -// Unary operators - -FakeComplex operator+( const FakeComplex& val ) -{ - return val; -} -FakeComplex operator-( const FakeComplex& val ) -{ - return {-val.real, -val.imag}; -} - -// Binary homogeneous operators - -FakeComplex operator+(const FakeComplex& z, const FakeComplex& w) -{ - return {z.real + w.real, z.imag + w.imag}; -} -FakeComplex operator-(const FakeComplex& z, const FakeComplex& w) -{ - return {z.real - w.real, z.imag - w.imag}; -} -FakeComplex operator*(const FakeComplex& z, const FakeComplex& w) -{ - return {z.real * w.real - z.imag * w.imag, - z.imag * w.real + z.real * w.imag}; -} -FakeComplex operator/(const FakeComplex& z, const FakeComplex& w) -{ - // just for illustration; please don't implement it this way. - const auto w_mag = w.real * w.real + w.imag * w.imag; - return {(z.real * w.real + z.imag * w.imag) / w_mag, - (z.imag * w.real - z.real * w.imag) / w_mag}; -} - -// Binary (complex,real) operators - -FakeComplex operator+(const FakeComplex& z, const double w) -{ - return {z.real + w, z.imag}; -} -FakeComplex operator-(const FakeComplex& z, const double w) -{ - return {z.real - w, z.imag}; -} -FakeComplex operator*(const FakeComplex& z, const double w) -{ - return {z.real * w, z.imag * w}; -} -FakeComplex operator/(const FakeComplex& z, const double w) -{ - return {z.real / w, z.imag / w}; -} - -// Binary (real,complex) operators - -FakeComplex operator+(const double z, const FakeComplex& w) -{ - return {z + w.real, z + w.imag}; -} -FakeComplex operator-(const double z, const FakeComplex& w) -{ - return {z - w.real, -w.imag}; -} -FakeComplex operator*(const double z, const FakeComplex& w) -{ - return {z * w.real, z * w.imag}; -} -FakeComplex operator/(const double z, const FakeComplex& w) -{ - // just for illustration; please don't implement it this way. - const auto w_mag = w.real * w.real + w.imag * w.imag; - return { - (z * w.real) / w_mag, - (-(z * w.imag)) / w_mag - }; -} - // Specialize test helper traits (P1673 does NOT need these) namespace test_helpers { @@ -205,18 +33,6 @@ static constexpr bool is_atomic_ref_not_arithmetic_v> = ! std } // namespace test_helpers -// FakeComplex conj implementation -FakeComplex conj(const FakeComplex& z) { return {z.real, -z.imag}; } - -// FakeComplex abs implementation -auto abs(const FakeComplex& z) { return sqrt(z.real * z.real + z.imag * z.imag); } - -// FakeComplex real implementation -auto real(const FakeComplex& z) { return z.real; } - -// FakeComplex imag implementation -auto imag(const FakeComplex& z) { return z.imag; } - /////////////////////////////////////////////////////////// // conj_if_needed tests /////////////////////////////////////////////////////////// @@ -1078,148 +894,6 @@ void test_FakeComplex_scaled_scalar(const ScalingFactor& scalingFactor) } namespace { - TEST(proxy_refs, conj_if_needed) - { - test_complex_conj_if_needed(); - test_complex_conj_if_needed(); - test_complex_conj_if_needed(); - - test_real_conj_if_needed(); - test_real_conj_if_needed(); - test_real_conj_if_needed(); - - test_real_conj_if_needed(); - test_real_conj_if_needed(); - test_real_conj_if_needed(); - test_real_conj_if_needed(); - } - - template - void test_imag_part_complex() - { - using std::experimental::linalg::impl::imag_part; - std::complex z{R(3.0), R(4.0)}; - auto z_imag = imag_part(z); - EXPECT_EQ(z_imag, R(4.0)); - static_assert(std::is_same_v); - } - template - void test_imag_part_floating_point() - { - using std::experimental::linalg::impl::imag_part; - T x = 9.0; - auto x_imag = imag_part(x); - EXPECT_EQ(x_imag, T(0.0)); - static_assert(std::is_same_v); - } - template - void test_imag_part_integral() - { - using std::experimental::linalg::impl::imag_part; - T x = 3; - auto x_imag = imag_part(x); - EXPECT_EQ(x_imag, T(0)); - static_assert(std::is_same_v); - } - - TEST(proxy_refs, imag_part) - { - test_imag_part_complex(); - test_imag_part_complex(); - test_imag_part_complex(); - - test_imag_part_floating_point(); - test_imag_part_floating_point(); - test_imag_part_floating_point(); - - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - - { - using std::experimental::linalg::impl::imag_part; - FakeComplex z{3.0, 4.0}; - auto z_imag = imag_part(z); - EXPECT_EQ(z_imag, 4.0); - static_assert(std::is_same_v); - } - { - using std::experimental::linalg::impl::imag_part; - FakeRealNumber x{3.0}; - auto x_imag = imag_part(x); - EXPECT_EQ(x_imag, FakeRealNumber{}); - static_assert(std::is_same_v); - } - } - - template - void test_real_part_complex() - { - using std::experimental::linalg::impl::real_part; - std::complex z{R(3.0), R(4.0)}; - auto z_imag = real_part(z); - EXPECT_EQ(z_imag, R(3.0)); - static_assert(std::is_same_v); - } - template - void test_real_part_floating_point() - { - using std::experimental::linalg::impl::real_part; - T x = 9.0; - auto x_imag = real_part(x); - EXPECT_EQ(x_imag, T(9.0)); - static_assert(std::is_same_v); - } - template - void test_real_part_integral() - { - using std::experimental::linalg::impl::real_part; - T x = 3; - auto x_imag = real_part(x); - EXPECT_EQ(x_imag, T(3)); - static_assert(std::is_same_v); - } - - TEST(proxy_refs, real_part) - { - test_real_part_complex(); - test_real_part_complex(); - test_real_part_complex(); - - test_real_part_floating_point(); - test_real_part_floating_point(); - test_real_part_floating_point(); - - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - - { - using std::experimental::linalg::impl::real_part; - FakeComplex z{3.0, 4.0}; - auto z_imag = real_part(z); - EXPECT_EQ(z_imag, 3.0); - static_assert(std::is_same_v); - } - { - using std::experimental::linalg::impl::real_part; - FakeRealNumber x{3.0}; - auto x_real = real_part(x); - EXPECT_EQ(x_real, FakeRealNumber{3.0}); - static_assert(std::is_same_v); - } - } - TEST(proxy_refs, conjugated_scalar) { test_complex_conjugated_scalar(); diff --git a/tests/native/test_numbers.hpp b/tests/native/test_numbers.hpp new file mode 100644 index 00000000..9d56d145 --- /dev/null +++ b/tests/native/test_numbers.hpp @@ -0,0 +1,228 @@ +/* +//@HEADER +// ************************************************************************ +// +// Kokkos v. 2.0 +// Copyright (2019) Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. // +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Christian R. Trott (crtrott@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_TEST_NUMBERS_HPP_ +#define LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_TEST_NUMBERS_HPP_ + +#define P1673_CONJUGATED_SCALAR_ARITHMETIC_OPERATORS_REFERENCE_OVERLOADS 1 + +#include "gtest/gtest.h" +#include + +/////////////////////////////////////////////////////////// +// Custom real number type for tests +/////////////////////////////////////////////////////////// + +struct FakeRealNumber { + float value; + +#ifdef __cpp_impl_three_way_comparison + bool operator==(const FakeRealNumber&) const = default; +#else + friend bool operator==(const FakeRealNumber& x, const FakeRealNumber& y) + { + return x.value == y.value; + } +#endif +}; + +// conj_if_needed assumes that FakeRealNumber is a real number, +// because it doesn't have an ADL-accessible definition of conj. +FakeRealNumber conj(const FakeRealNumber& x) { return x; } + +/////////////////////////////////////////////////////////// +// Custom real number type for tests +/////////////////////////////////////////////////////////// + +struct FakeComplex { + double real; + double imag; + +#ifdef __cpp_impl_three_way_comparison + bool operator==(const FakeComplex&) const = default; +#else + friend bool operator==(const FakeComplex& x, const FakeComplex& y) + { + return x.real == y.real && x.imag == y.imag; + } +#endif + + constexpr FakeComplex& operator+=(const FakeComplex& other) + { + real += other.real; + imag += other.imag; + return *this; + } + constexpr FakeComplex& operator-=(const FakeComplex& other) + { + real -= other.real; + imag -= other.imag; + return *this; + } + constexpr FakeComplex& operator*=(const FakeComplex& other) + { + real = real * other.real - imag * other.imag; + imag = imag * other.real + real * other.imag; + return *this; + } + constexpr FakeComplex& operator/=(const FakeComplex& other) + { + // just for illustration; please don't implement it this way. + const auto other_mag = other.real * other.real + other.imag * other.imag; + real = (real * other.real + imag * other.imag) / other_mag; + imag = (imag * other.real - real * other.imag) / other_mag; + return *this; + } + + constexpr FakeComplex& operator+=(const double other) + { + real += other; + return *this; + } + constexpr FakeComplex& operator-=(const double other) + { + real -= other; + return *this; + } + constexpr FakeComplex& operator*=(const double other) + { + real *= other; + imag *= other; + return *this; + } + constexpr FakeComplex& operator/=(const double other) + { + real /= other; + imag /= other; + return *this; + } +}; + +// Unary operators + +FakeComplex operator+(const FakeComplex& val) +{ + return val; +} +FakeComplex operator-(const FakeComplex& val) +{ + return { -val.real, -val.imag }; +} + +// Binary homogeneous operators + +FakeComplex operator+(const FakeComplex& z, const FakeComplex& w) +{ + return { z.real + w.real, z.imag + w.imag }; +} +FakeComplex operator-(const FakeComplex& z, const FakeComplex& w) +{ + return { z.real - w.real, z.imag - w.imag }; +} +FakeComplex operator*(const FakeComplex& z, const FakeComplex& w) +{ + return { z.real * w.real - z.imag * w.imag, + z.imag * w.real + z.real * w.imag }; +} +FakeComplex operator/(const FakeComplex& z, const FakeComplex& w) +{ + // just for illustration; please don't implement it this way. + const auto w_mag = w.real * w.real + w.imag * w.imag; + return { (z.real * w.real + z.imag * w.imag) / w_mag, + (z.imag * w.real - z.real * w.imag) / w_mag }; +} + +// Binary (complex,real) operators + +FakeComplex operator+(const FakeComplex& z, const double w) +{ + return { z.real + w, z.imag }; +} +FakeComplex operator-(const FakeComplex& z, const double w) +{ + return { z.real - w, z.imag }; +} +FakeComplex operator*(const FakeComplex& z, const double w) +{ + return { z.real * w, z.imag * w }; +} +FakeComplex operator/(const FakeComplex& z, const double w) +{ + return { z.real / w, z.imag / w }; +} + +// Binary (real,complex) operators + +FakeComplex operator+(const double z, const FakeComplex& w) +{ + return { z + w.real, z + w.imag }; +} +FakeComplex operator-(const double z, const FakeComplex& w) +{ + return { z - w.real, -w.imag }; +} +FakeComplex operator*(const double z, const FakeComplex& w) +{ + return { z * w.real, z * w.imag }; +} +FakeComplex operator/(const double z, const FakeComplex& w) +{ + // just for illustration; please don't implement it this way. + const auto w_mag = w.real * w.real + w.imag * w.imag; + return { + (z * w.real) / w_mag, + (-(z * w.imag)) / w_mag + }; +} + +// conj_if_needed knows that FakeComplex is a complex number +// because it has this ADL-findable conj function. +// Ditto for abs, real, and imag below. +FakeComplex conj(const FakeComplex& z) { return { z.real, -z.imag }; } + +auto abs(const FakeComplex& z) { return sqrt(z.real * z.real + z.imag * z.imag); } + +auto real(const FakeComplex& z) { return z.real; } + +auto imag(const FakeComplex& z) { return z.imag; } + +#endif //LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_TEST_NUMBERS_HPP_ diff --git a/tests/native/test_test_numbers.cpp b/tests/native/test_test_numbers.cpp new file mode 100644 index 00000000..bfdcdec7 --- /dev/null +++ b/tests/native/test_test_numbers.cpp @@ -0,0 +1,223 @@ +#define MDSPAN_USE_PAREN_OPERATOR 1 +#define P1673_CONJUGATED_SCALAR_ARITHMETIC_OPERATORS_REFERENCE_OVERLOADS 1 + +#include "gtest/gtest.h" +#include "./test_numbers.hpp" +#include + +// Specialize test helper traits (P1673 does NOT need these) +namespace test_helpers { + +template +constexpr bool is_complex_v = false; + +template<> +constexpr bool is_complex_v> = true; + +template<> +constexpr bool is_complex_v> = true; + +template<> +constexpr bool is_complex_v> = true; + +template<> +constexpr bool is_complex_v = true; + +template +static constexpr bool is_atomic_ref_not_arithmetic_v = false; + +#if defined(__cpp_lib_atomic_ref) && defined(LINALG_ENABLE_ATOMIC_REF) +template +static constexpr bool is_atomic_ref_not_arithmetic_v> = ! std::is_arithmetic_v; +#endif + +} // namespace test_helpers + +/////////////////////////////////////////////////////////// +// conj_if_needed tests +/////////////////////////////////////////////////////////// + +namespace { + template + void test_real_conj_if_needed() + { + using std::experimental::linalg::impl::conj_if_needed; + + Real z(2.0); + const Real z_conj_expected(2.0); + + auto z_conj = conj_if_needed(z); + static_assert(std::is_same_v); + EXPECT_EQ(z_conj, z_conj_expected); + } + + template + void test_any_complex_conj_if_needed() + { + using std::experimental::linalg::impl::conj_if_needed; + + Complex z(2.0, -3.0); + Complex z_orig(2.0, -3.0); + const Complex z_conj_expected(2.0, 3.0); + + auto z_conj = conj_if_needed(z); + static_assert(std::is_same_v); + EXPECT_EQ(z_conj, z_conj_expected); + EXPECT_EQ(z, z_orig); // conj didn't change its input + } + + template + void test_std_complex_conj_if_needed() + { + test_any_complex_conj_if_needed>(); + } + + void test_FakeComplex_conj_if_needed() + { + test_any_complex_conj_if_needed(); + } + + TEST(test_numbers, conj_if_needed) + { + test_std_complex_conj_if_needed(); + test_std_complex_conj_if_needed(); + test_std_complex_conj_if_needed(); + + test_FakeComplex_conj_if_needed(); + + test_real_conj_if_needed(); + test_real_conj_if_needed(); + test_real_conj_if_needed(); + + test_real_conj_if_needed(); + test_real_conj_if_needed(); + test_real_conj_if_needed(); + test_real_conj_if_needed(); + } + + template + void test_imag_part_complex() + { + using std::experimental::linalg::impl::imag_part; + std::complex z{R(3.0), R(4.0)}; + auto z_imag = imag_part(z); + EXPECT_EQ(z_imag, R(4.0)); + static_assert(std::is_same_v); + } + template + void test_imag_part_floating_point() + { + using std::experimental::linalg::impl::imag_part; + T x = 9.0; + auto x_imag = imag_part(x); + EXPECT_EQ(x_imag, T(0.0)); + static_assert(std::is_same_v); + } + template + void test_imag_part_integral() + { + using std::experimental::linalg::impl::imag_part; + T x = 3; + auto x_imag = imag_part(x); + EXPECT_EQ(x_imag, T(0)); + static_assert(std::is_same_v); + } + + TEST(test_numbers, imag_part) + { + test_imag_part_complex(); + test_imag_part_complex(); + test_imag_part_complex(); + + test_imag_part_floating_point(); + test_imag_part_floating_point(); + test_imag_part_floating_point(); + + test_imag_part_integral(); + test_imag_part_integral(); + test_imag_part_integral(); + test_imag_part_integral(); + test_imag_part_integral(); + test_imag_part_integral(); + test_imag_part_integral(); + test_imag_part_integral(); + + { + using std::experimental::linalg::impl::imag_part; + FakeComplex z{3.0, 4.0}; + auto z_imag = imag_part(z); + EXPECT_EQ(z_imag, 4.0); + static_assert(std::is_same_v); + } + { + using std::experimental::linalg::impl::imag_part; + FakeRealNumber x{3.0}; + auto x_imag = imag_part(x); + EXPECT_EQ(x_imag, FakeRealNumber{}); + static_assert(std::is_same_v); + } + } + + template + void test_real_part_complex() + { + using std::experimental::linalg::impl::real_part; + std::complex z{R(3.0), R(4.0)}; + auto z_imag = real_part(z); + EXPECT_EQ(z_imag, R(3.0)); + static_assert(std::is_same_v); + } + template + void test_real_part_floating_point() + { + using std::experimental::linalg::impl::real_part; + T x = 9.0; + auto x_imag = real_part(x); + EXPECT_EQ(x_imag, T(9.0)); + static_assert(std::is_same_v); + } + template + void test_real_part_integral() + { + using std::experimental::linalg::impl::real_part; + T x = 3; + auto x_imag = real_part(x); + EXPECT_EQ(x_imag, T(3)); + static_assert(std::is_same_v); + } + + TEST(test_numbers, real_part) + { + test_real_part_complex(); + test_real_part_complex(); + test_real_part_complex(); + + test_real_part_floating_point(); + test_real_part_floating_point(); + test_real_part_floating_point(); + + test_real_part_integral(); + test_real_part_integral(); + test_real_part_integral(); + test_real_part_integral(); + test_real_part_integral(); + test_real_part_integral(); + test_real_part_integral(); + test_real_part_integral(); + + { + using std::experimental::linalg::impl::real_part; + FakeComplex z{ 3.0, 4.0 }; + auto z_imag = real_part(z); + EXPECT_EQ(z_imag, 3.0); + static_assert(std::is_same_v); + } + { + using std::experimental::linalg::impl::real_part; + FakeRealNumber x{ 3.0 }; + auto x_real = real_part(x); + EXPECT_EQ(x_real, FakeRealNumber{ 3.0 }); + static_assert(std::is_same_v); + } + } +} // namespace (anonymous) From fe3b2ae7907ab05ceb99adeeb898a4a6cea6ca31 Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 19:05:12 +0800 Subject: [PATCH 08/15] Implement real-if-needed & imag-if-needed ...and test them. --- .../__p1673_bits/conjugate_if_needed.hpp | 2 +- .../__p1673_bits/imag_if_needed.hpp | 96 ++++++++++++++ .../__p1673_bits/proxy_reference.hpp | 16 --- .../__p1673_bits/real_if_needed.hpp | 96 ++++++++++++++ include/experimental/linalg | 3 +- tests/native/conjugated.cpp | 1 - tests/native/proxy_refs.cpp | 1 + tests/native/scaled.cpp | 1 - tests/native/test_test_numbers.cpp | 118 +++++++++--------- 9 files changed, 255 insertions(+), 79 deletions(-) create mode 100644 include/experimental/__p1673_bits/imag_if_needed.hpp create mode 100644 include/experimental/__p1673_bits/real_if_needed.hpp diff --git a/include/experimental/__p1673_bits/conjugate_if_needed.hpp b/include/experimental/__p1673_bits/conjugate_if_needed.hpp index e789b01e..67f3fefc 100644 --- a/include/experimental/__p1673_bits/conjugate_if_needed.hpp +++ b/include/experimental/__p1673_bits/conjugate_if_needed.hpp @@ -97,4 +97,4 @@ constexpr inline auto conj_if_needed = [](const auto& t) } // end namespace experimental } // end namespace std -#endif //LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_CONJUGATE_TRANSPOSED_HPP_ +#endif //LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_CONJUGATE_IF_NEEDED_HPP_ diff --git a/include/experimental/__p1673_bits/imag_if_needed.hpp b/include/experimental/__p1673_bits/imag_if_needed.hpp new file mode 100644 index 00000000..c94f4e9d --- /dev/null +++ b/include/experimental/__p1673_bits/imag_if_needed.hpp @@ -0,0 +1,96 @@ +/* +//@HEADER +// ************************************************************************ +// +// Kokkos v. 2.0 +// Copyright (2019) Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. // +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Christian R. Trott (crtrott@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_IMAG_IF_NEEDED_HPP_ +#define LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_IMAG_IF_NEEDED_HPP_ + +#include +#include + +namespace std { +namespace experimental { +inline namespace __p1673_version_0 { +namespace linalg { +namespace impl{ + +template +struct has_imag : std::false_type {}; + +// If I can find unqualified imag via overload resolution, +// then assume that imag(t) returns the imag part of t. +template +struct has_imag()), void())> : std::true_type {}; + +template +T imag_if_needed_impl(const T& t, std::false_type) +{ + // If imag(t) can't be ADL-found, then assume + // that T represents a noncomplex number type. + return T{}; +} + +template +auto imag_if_needed_impl(const T& t, std::true_type) +{ + if constexpr (std::is_arithmetic_v) { + // Overloads for integers have a return type of double. + // We want to preserve the input type T. + return T{}; + } else { + return imag(t); + } +} + +// Inline static variables require C++17. +constexpr inline auto imag_if_needed = [](const auto& t) +{ + using T = std::remove_const_t; + return imag_if_needed_impl(t, has_imag{}); +}; + +} // end namespace impl +} // end namespace linalg +} // end inline namespace __p1673_version_0 +} // end namespace experimental +} // end namespace std + +#endif //LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_IMAG_IF_NEEDED_HPP_ diff --git a/include/experimental/__p1673_bits/proxy_reference.hpp b/include/experimental/__p1673_bits/proxy_reference.hpp index ee41413c..202324c1 100644 --- a/include/experimental/__p1673_bits/proxy_reference.hpp +++ b/include/experimental/__p1673_bits/proxy_reference.hpp @@ -67,14 +67,6 @@ template static constexpr bool is_atomic_ref_not_arithmetic_v> = ! std::is_arithmetic_v; #endif -template -struct has_imag : std::false_type {}; - -// If I can find unqualified imag via overload resolution, -// then assume that imag(t) returns the imaginary part of t. -template -struct has_imag()), void())> : std::true_type {}; - template T imag_part_impl(const T& t, std::false_type) { @@ -97,14 +89,6 @@ auto imag_part(const T& t) return imag_part_impl(t, has_imag{}); } -template -struct has_real : std::false_type {}; - -// If I can find unqualified real via overload resolution, -// then assume that real(t) returns the real part of t. -template -struct has_real()), void())> : std::true_type {}; - template T real_part_impl(const T& t, std::false_type) { diff --git a/include/experimental/__p1673_bits/real_if_needed.hpp b/include/experimental/__p1673_bits/real_if_needed.hpp new file mode 100644 index 00000000..9fb16fe1 --- /dev/null +++ b/include/experimental/__p1673_bits/real_if_needed.hpp @@ -0,0 +1,96 @@ +/* +//@HEADER +// ************************************************************************ +// +// Kokkos v. 2.0 +// Copyright (2019) Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. // +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Christian R. Trott (crtrott@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_REAL_IF_NEEDED_HPP_ +#define LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_REAL_IF_NEEDED_HPP_ + +#include +#include + +namespace std { +namespace experimental { +inline namespace __p1673_version_0 { +namespace linalg { +namespace impl{ + +template +struct has_real : std::false_type {}; + +// If I can find unqualified real via overload resolution, +// then assume that real(t) returns the real part of t. +template +struct has_real()), void())> : std::true_type {}; + +template +T real_if_needed_impl(const T& t, std::false_type) +{ + // If real(t) can't be ADL-found, then assume + // that T represents a noncomplex number type. + return t; +} + +template +auto real_if_needed_impl(const T& t, std::true_type) +{ + if constexpr (std::is_arithmetic_v) { + // Overloads for integers have a return type of double. + // We want to preserve the input type T. + return t; + } else { + return real(t); + } +} + +// Inline static variables require C++17. +constexpr inline auto real_if_needed = [](const auto& t) +{ + using T = std::remove_const_t; + return real_if_needed_impl(t, has_real{}); +}; + +} // end namespace impl +} // end namespace linalg +} // end inline namespace __p1673_version_0 +} // end namespace experimental +} // end namespace std + +#endif //LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_REAL_IF_NEEDED_HPP_ diff --git a/include/experimental/linalg b/include/experimental/linalg index 6f2ff697..72b6b17b 100644 --- a/include/experimental/linalg +++ b/include/experimental/linalg @@ -52,7 +52,8 @@ #include "__p1673_bits/layout_triangle.hpp" #include "__p1673_bits/packed_layout.hpp" #include "__p1673_bits/conjugate_if_needed.hpp" -#include "__p1673_bits/proxy_reference.hpp" +#include "__p1673_bits/real_if_needed.hpp" +#include "__p1673_bits/imag_if_needed.hpp" #include "__p1673_bits/scaled.hpp" #include "__p1673_bits/conjugated.hpp" #include "__p1673_bits/transposed.hpp" diff --git a/tests/native/conjugated.cpp b/tests/native/conjugated.cpp index 3ee0e078..1498a7c0 100644 --- a/tests/native/conjugated.cpp +++ b/tests/native/conjugated.cpp @@ -10,7 +10,6 @@ namespace { { using std::experimental::linalg::conjugate_accessor; using std::experimental::default_accessor; - using std::experimental::linalg::conjugated_scalar; using value_type = std::remove_cv_t; constexpr bool is_arith = std::is_arithmetic_v; diff --git a/tests/native/proxy_refs.cpp b/tests/native/proxy_refs.cpp index 759b1917..611c9ffc 100644 --- a/tests/native/proxy_refs.cpp +++ b/tests/native/proxy_refs.cpp @@ -4,6 +4,7 @@ #include "gtest/gtest.h" #include "./test_numbers.hpp" #include +#include "experimental/__p1673_bits/proxy_reference.hpp" // Specialize test helper traits (P1673 does NOT need these) namespace test_helpers { diff --git a/tests/native/scaled.cpp b/tests/native/scaled.cpp index 4257ea5c..ac5484b3 100644 --- a/tests/native/scaled.cpp +++ b/tests/native/scaled.cpp @@ -10,7 +10,6 @@ namespace { void test_scaled_accessor_element_constification() { using std::experimental::linalg::scaled_accessor; - using std::experimental::linalg::scaled_scalar; using nc_def_acc_type = default_accessor; using c_def_acc_type = diff --git a/tests/native/test_test_numbers.cpp b/tests/native/test_test_numbers.cpp index bfdcdec7..94c80789 100644 --- a/tests/native/test_test_numbers.cpp +++ b/tests/native/test_test_numbers.cpp @@ -96,126 +96,126 @@ namespace { } template - void test_imag_part_complex() + void test_imag_if_needed_complex() { - using std::experimental::linalg::impl::imag_part; + using std::experimental::linalg::impl::imag_if_needed; std::complex z{R(3.0), R(4.0)}; - auto z_imag = imag_part(z); + auto z_imag = imag_if_needed(z); EXPECT_EQ(z_imag, R(4.0)); static_assert(std::is_same_v); } template - void test_imag_part_floating_point() + void test_imag_if_needed_floating_point() { - using std::experimental::linalg::impl::imag_part; + using std::experimental::linalg::impl::imag_if_needed; T x = 9.0; - auto x_imag = imag_part(x); + auto x_imag = imag_if_needed(x); EXPECT_EQ(x_imag, T(0.0)); static_assert(std::is_same_v); } template - void test_imag_part_integral() + void test_imag_if_needed_integral() { - using std::experimental::linalg::impl::imag_part; + using std::experimental::linalg::impl::imag_if_needed; T x = 3; - auto x_imag = imag_part(x); + auto x_imag = imag_if_needed(x); EXPECT_EQ(x_imag, T(0)); static_assert(std::is_same_v); } - TEST(test_numbers, imag_part) + TEST(test_numbers, imag_if_needed) { - test_imag_part_complex(); - test_imag_part_complex(); - test_imag_part_complex(); + test_imag_if_needed_complex(); + test_imag_if_needed_complex(); + test_imag_if_needed_complex(); - test_imag_part_floating_point(); - test_imag_part_floating_point(); - test_imag_part_floating_point(); - - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); + test_imag_if_needed_floating_point(); + test_imag_if_needed_floating_point(); + test_imag_if_needed_floating_point(); + + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); { - using std::experimental::linalg::impl::imag_part; + using std::experimental::linalg::impl::imag_if_needed; FakeComplex z{3.0, 4.0}; - auto z_imag = imag_part(z); + auto z_imag = imag_if_needed(z); EXPECT_EQ(z_imag, 4.0); static_assert(std::is_same_v); } { - using std::experimental::linalg::impl::imag_part; + using std::experimental::linalg::impl::imag_if_needed; FakeRealNumber x{3.0}; - auto x_imag = imag_part(x); + auto x_imag = imag_if_needed(x); EXPECT_EQ(x_imag, FakeRealNumber{}); static_assert(std::is_same_v); } } template - void test_real_part_complex() + void test_real_if_needed_complex() { - using std::experimental::linalg::impl::real_part; + using std::experimental::linalg::impl::real_if_needed; std::complex z{R(3.0), R(4.0)}; - auto z_imag = real_part(z); + auto z_imag = real_if_needed(z); EXPECT_EQ(z_imag, R(3.0)); static_assert(std::is_same_v); } template - void test_real_part_floating_point() + void test_real_if_needed_floating_point() { - using std::experimental::linalg::impl::real_part; + using std::experimental::linalg::impl::real_if_needed; T x = 9.0; - auto x_imag = real_part(x); + auto x_imag = real_if_needed(x); EXPECT_EQ(x_imag, T(9.0)); static_assert(std::is_same_v); } template - void test_real_part_integral() + void test_real_if_needed_integral() { - using std::experimental::linalg::impl::real_part; + using std::experimental::linalg::impl::real_if_needed; T x = 3; - auto x_imag = real_part(x); + auto x_imag = real_if_needed(x); EXPECT_EQ(x_imag, T(3)); static_assert(std::is_same_v); } - TEST(test_numbers, real_part) + TEST(test_numbers, real_if_needed) { - test_real_part_complex(); - test_real_part_complex(); - test_real_part_complex(); - - test_real_part_floating_point(); - test_real_part_floating_point(); - test_real_part_floating_point(); - - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); + test_real_if_needed_complex(); + test_real_if_needed_complex(); + test_real_if_needed_complex(); + + test_real_if_needed_floating_point(); + test_real_if_needed_floating_point(); + test_real_if_needed_floating_point(); + + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); { - using std::experimental::linalg::impl::real_part; + using std::experimental::linalg::impl::real_if_needed; FakeComplex z{ 3.0, 4.0 }; - auto z_imag = real_part(z); + auto z_imag = real_if_needed(z); EXPECT_EQ(z_imag, 3.0); static_assert(std::is_same_v); } { - using std::experimental::linalg::impl::real_part; + using std::experimental::linalg::impl::real_if_needed; FakeRealNumber x{ 3.0 }; - auto x_real = real_part(x); + auto x_real = real_if_needed(x); EXPECT_EQ(x_real, FakeRealNumber{ 3.0 }); static_assert(std::is_same_v); } From aa6d9a667dff3193ca6220e84d4deba66cb4baed Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 19:13:54 +0800 Subject: [PATCH 09/15] Rename conjugate_if_needed.hpp to conj_if_needed.hpp This better reflects the header's contents. Also, fix the kokkos-kernels implementation, as it no longer needs the is_complex trait to determine if conj should be called on a number type. --- .../{conjugate_if_needed.hpp => conj_if_needed.hpp} | 0 include/experimental/__p1673_bits/proxy_reference.hpp | 2 +- include/experimental/linalg | 2 +- .../__p1673_bits/kokkos-kernels/kokkos_conjugate.hpp | 8 +++++--- 4 files changed, 7 insertions(+), 5 deletions(-) rename include/experimental/__p1673_bits/{conjugate_if_needed.hpp => conj_if_needed.hpp} (100%) diff --git a/include/experimental/__p1673_bits/conjugate_if_needed.hpp b/include/experimental/__p1673_bits/conj_if_needed.hpp similarity index 100% rename from include/experimental/__p1673_bits/conjugate_if_needed.hpp rename to include/experimental/__p1673_bits/conj_if_needed.hpp diff --git a/include/experimental/__p1673_bits/proxy_reference.hpp b/include/experimental/__p1673_bits/proxy_reference.hpp index 202324c1..2c6014b2 100644 --- a/include/experimental/__p1673_bits/proxy_reference.hpp +++ b/include/experimental/__p1673_bits/proxy_reference.hpp @@ -43,7 +43,7 @@ #ifndef LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_PROXY_REFERENCE_HPP_ #define LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_PROXY_REFERENCE_HPP_ -#include "conjugate_if_needed.hpp" +#include "conj_if_needed.hpp" #if defined(__cpp_lib_atomic_ref) && defined(LINALG_ENABLE_ATOMIC_REF) # include #endif diff --git a/include/experimental/linalg b/include/experimental/linalg index 72b6b17b..c4f65f16 100644 --- a/include/experimental/linalg +++ b/include/experimental/linalg @@ -51,7 +51,7 @@ #include "__p1673_bits/layout_tags.hpp" #include "__p1673_bits/layout_triangle.hpp" #include "__p1673_bits/packed_layout.hpp" -#include "__p1673_bits/conjugate_if_needed.hpp" +#include "__p1673_bits/conj_if_needed.hpp" #include "__p1673_bits/real_if_needed.hpp" #include "__p1673_bits/imag_if_needed.hpp" #include "__p1673_bits/scaled.hpp" diff --git a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/kokkos_conjugate.hpp b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/kokkos_conjugate.hpp index cd934857..4247f2ef 100644 --- a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/kokkos_conjugate.hpp +++ b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/kokkos_conjugate.hpp @@ -43,15 +43,17 @@ #ifndef LINALG_TPLIMPLEMENTATIONS_INCLUDE_EXPERIMENTAL___P1673_BITS_KOKKOSKERNELS_CONJUGATE_IF_NEEDED_HPP_ #define LINALG_TPLIMPLEMENTATIONS_INCLUDE_EXPERIMENTAL___P1673_BITS_KOKKOSKERNELS_CONJUGATE_IF_NEEDED_HPP_ -#include "experimental/__p1673_bits/conjugate_if_needed.hpp" +#include "experimental/__p1673_bits/conj_if_needed.hpp" namespace std { namespace experimental { namespace linalg { namespace impl{ -// add Kokkos::complex to scalar types conjugated by conj_if_needed() -template struct is_complex> : std::true_type{}; +// conj_if_needed doesn't use an is_complex trait. +// Instead, it checks whether conj(x) (namespace-unqualified) is a valid expression, +// calls that if so, else assumes that x represents a real number and returns x. +// Thus, we don't actually need to do anything here. } // end namespace impl } // end namespace linalg From eb3a0ba64a8dccc278186d1e1680d0dbf006704b Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 19:34:10 +0800 Subject: [PATCH 10/15] Simplify test filename --- tests/native/CMakeLists.txt | 2 +- tests/native/{test_test_numbers.cpp => test_numbers.cpp} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/native/{test_test_numbers.cpp => test_numbers.cpp} (100%) diff --git a/tests/native/CMakeLists.txt b/tests/native/CMakeLists.txt index c3782457..ba528919 100644 --- a/tests/native/CMakeLists.txt +++ b/tests/native/CMakeLists.txt @@ -33,7 +33,7 @@ linalg_add_test(scale) linalg_add_test(scaled) linalg_add_test(swap) linalg_add_test(symm) -linalg_add_test(test_test_numbers) +linalg_add_test(test_numbers) linalg_add_test(transposed) linalg_add_test(trmm) linalg_add_test(trsm) diff --git a/tests/native/test_test_numbers.cpp b/tests/native/test_numbers.cpp similarity index 100% rename from tests/native/test_test_numbers.cpp rename to tests/native/test_numbers.cpp From 16754d4525e4ad855da782c239cbd6c83e930329 Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 19:36:37 +0800 Subject: [PATCH 11/15] Remove proxy_reference.hpp from linalg headers scaled_accessor and conjugate_accessor no longer use proxy reference types, so we don't need to include that header in linalg any more. We still have a test for the proxy reference types, so move proxy_reference.hpp to the test directory. --- .../__p1673_bits => tests/native}/proxy_reference.hpp | 2 +- tests/native/proxy_refs.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename {include/experimental/__p1673_bits => tests/native}/proxy_reference.hpp (99%) diff --git a/include/experimental/__p1673_bits/proxy_reference.hpp b/tests/native/proxy_reference.hpp similarity index 99% rename from include/experimental/__p1673_bits/proxy_reference.hpp rename to tests/native/proxy_reference.hpp index 2c6014b2..2b653457 100644 --- a/include/experimental/__p1673_bits/proxy_reference.hpp +++ b/tests/native/proxy_reference.hpp @@ -43,7 +43,7 @@ #ifndef LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_PROXY_REFERENCE_HPP_ #define LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_PROXY_REFERENCE_HPP_ -#include "conj_if_needed.hpp" +#include "experimental/__p1673_bits/conj_if_needed.hpp" #if defined(__cpp_lib_atomic_ref) && defined(LINALG_ENABLE_ATOMIC_REF) # include #endif diff --git a/tests/native/proxy_refs.cpp b/tests/native/proxy_refs.cpp index 611c9ffc..e4cbf9a9 100644 --- a/tests/native/proxy_refs.cpp +++ b/tests/native/proxy_refs.cpp @@ -4,7 +4,7 @@ #include "gtest/gtest.h" #include "./test_numbers.hpp" #include -#include "experimental/__p1673_bits/proxy_reference.hpp" +#include "./proxy_reference.hpp" // Specialize test helper traits (P1673 does NOT need these) namespace test_helpers { From 21781a1cfa399310e294c5004e4849d0eb1ad4a0 Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Wed, 26 Jul 2023 20:14:55 +0800 Subject: [PATCH 12/15] Remove unused code --- tests/native/proxy_refs.cpp | 15 --------------- tests/native/test_numbers.cpp | 28 ---------------------------- 2 files changed, 43 deletions(-) diff --git a/tests/native/proxy_refs.cpp b/tests/native/proxy_refs.cpp index e4cbf9a9..b205d866 100644 --- a/tests/native/proxy_refs.cpp +++ b/tests/native/proxy_refs.cpp @@ -9,21 +9,6 @@ // Specialize test helper traits (P1673 does NOT need these) namespace test_helpers { -template -constexpr bool is_complex_v = false; - -template<> -constexpr bool is_complex_v> = true; - -template<> -constexpr bool is_complex_v> = true; - -template<> -constexpr bool is_complex_v> = true; - -template<> -constexpr bool is_complex_v = true; - template static constexpr bool is_atomic_ref_not_arithmetic_v = false; diff --git a/tests/native/test_numbers.cpp b/tests/native/test_numbers.cpp index 94c80789..4c8e45e5 100644 --- a/tests/native/test_numbers.cpp +++ b/tests/native/test_numbers.cpp @@ -5,34 +5,6 @@ #include "./test_numbers.hpp" #include -// Specialize test helper traits (P1673 does NOT need these) -namespace test_helpers { - -template -constexpr bool is_complex_v = false; - -template<> -constexpr bool is_complex_v> = true; - -template<> -constexpr bool is_complex_v> = true; - -template<> -constexpr bool is_complex_v> = true; - -template<> -constexpr bool is_complex_v = true; - -template -static constexpr bool is_atomic_ref_not_arithmetic_v = false; - -#if defined(__cpp_lib_atomic_ref) && defined(LINALG_ENABLE_ATOMIC_REF) -template -static constexpr bool is_atomic_ref_not_arithmetic_v> = ! std::is_arithmetic_v; -#endif - -} // namespace test_helpers - /////////////////////////////////////////////////////////// // conj_if_needed tests /////////////////////////////////////////////////////////// From 0b09f562bec17490f1655a5f74b6053a9b476331 Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Fri, 28 Jul 2023 16:25:55 +0800 Subject: [PATCH 13/15] Add tests mixing result of scaled w/ proxy reference accessor --- tests/native/CMakeLists.txt | 1 + tests/native/mixed_accessors.cpp | 211 +++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 tests/native/mixed_accessors.cpp diff --git a/tests/native/CMakeLists.txt b/tests/native/CMakeLists.txt index ba528919..c2eb6669 100644 --- a/tests/native/CMakeLists.txt +++ b/tests/native/CMakeLists.txt @@ -27,6 +27,7 @@ linalg_add_test(idx_abs_max) linalg_add_test(iterator) linalg_add_test(matrix_inf_norm) linalg_add_test(matrix_one_norm) +linalg_add_test(mixed_accessors) linalg_add_test(norm2) linalg_add_test(proxy_refs) linalg_add_test(scale) diff --git a/tests/native/mixed_accessors.cpp b/tests/native/mixed_accessors.cpp new file mode 100644 index 00000000..9a1ae307 --- /dev/null +++ b/tests/native/mixed_accessors.cpp @@ -0,0 +1,211 @@ +#include "./gtest_fixtures.hpp" +#include +#include + +// Proxy reference type for tests. +template +class my_proxy_reference { +private: + using this_type = my_proxy_reference; + using element_type = ElementType; + using value_type = std::remove_cv_t; + using reference = element_type&; + + element_type* ptr_; + +public: + explicit my_proxy_reference(reference ref) : ptr_(&ref) {} + my_proxy_reference(const my_proxy_reference& shallow_copy) : ptr_(shallow_copy.ptr_) {} + // my_proxy_reference is not copy assignable. + my_proxy_reference& operator=(const my_proxy_reference&) = delete; + + value_type operator=(value_type desired) const noexcept { + *ptr_ = desired; + return desired; + } + + operator value_type() const noexcept { + return value_type(*ptr_); + } +}; + +template +struct my_proxy_reference_accessor { + using offset_policy = my_proxy_reference_accessor; + using element_type = ElementType; + using reference = my_proxy_reference; + using data_handle_type = ElementType*; + + MDSPAN_INLINE_FUNCTION_DEFAULTED constexpr my_proxy_reference_accessor() noexcept = default; + + MDSPAN_TEMPLATE_REQUIRES( + class OtherElementType, + /* requires */ ( + _MDSPAN_TRAIT(std::is_convertible, OtherElementType(*)[], element_type(*)[]) + ) + ) + MDSPAN_INLINE_FUNCTION + constexpr my_proxy_reference_accessor(my_proxy_reference_accessor) noexcept {} + + MDSPAN_INLINE_FUNCTION + constexpr data_handle_type + offset(data_handle_type p, size_t i) const noexcept { + return p + i; + } + + MDSPAN_FORCE_INLINE_FUNCTION + constexpr reference access(data_handle_type p, size_t i) const noexcept { + return reference{ p[i] }; + } +}; + +#if defined(__cpp_lib_atomic_ref) +// P2689 proposes atomic_accessor. This is a simpler version. +// The point of this is to have an accessor whose "reference" +// is a proxy reference type, instead of element_type&. +// In this case, the proxy reference type is atomic_ref, +// a C++20 feature. +// +// We want an accessor with a proxy reference +// because we want to test arithmetic expressions +// involving mdspan accesses that mix element_type +// and a proxy reference type. +// +// atomic_ref has overloaded arithmetic operators +// when T is an arithmetic type. It turns out we need +// those overloaded arithmetic operators. We can't ask mdspan +// to work miracles; the user's proxy reference type +// needs to have all the arithmetic operators needed +// for the arithmetic expressions that occur in the program. +template +struct atomic_accessor { + using offset_policy = atomic_accessor; + using element_type = ElementType; + using reference = std::atomic_ref; + using data_handle_type = ElementType*; + + MDSPAN_INLINE_FUNCTION_DEFAULTED constexpr atomic_accessor() noexcept = default; + + MDSPAN_TEMPLATE_REQUIRES( + class OtherElementType, + /* requires */ ( + _MDSPAN_TRAIT(std::is_convertible, OtherElementType(*)[], element_type(*)[]) + ) + ) + MDSPAN_INLINE_FUNCTION + constexpr atomic_accessor(atomic_accessor) noexcept {} + + MDSPAN_INLINE_FUNCTION + constexpr data_handle_type + offset(data_handle_type p, size_t i) const noexcept { + return p + i; + } + + MDSPAN_FORCE_INLINE_FUNCTION + constexpr reference access(data_handle_type p, size_t i) const noexcept { + return reference{ p[i] }; + } +}; +#endif // __cpp_lib_atomic_ref + +namespace { + using std::experimental::linalg::scaled; + + TEST(mixed_accessors, mdspan_int) + { + using real_t = int; + using scalar_t = int; + using extents_t = dextents; + using vector_t = mdspan; + + constexpr std::size_t vectorSize(5); + constexpr std::size_t storageSize = 2 * vectorSize; + std::vector storage(storageSize); + + vector_t x(storage.data(), vectorSize); + vector_t y(storage.data() + vectorSize, vectorSize); + + for (std::size_t k = 0; k < vectorSize; ++k) { + const scalar_t x_k(real_t(k) + 11); + const scalar_t y_k(real_t(k) + 5); + x(k) = x_k; + y(k) = y_k; + } + + mdspan> x_proxy(x.data_handle(), x.mapping()); + const int alpha = 2; + auto y_scaled = scaled(alpha, y); + for (std::size_t k = 0; k < vectorSize; ++k) { + ASSERT_EQ(x_proxy(k), real_t(k) + 11); + ASSERT_EQ(y_scaled(k), 2 * real_t(k) + 10); + + auto x_minus_y = x_proxy(k) - y_scaled(k); + static_assert(std::is_same_v); + EXPECT_EQ(x_minus_y, -real_t(k) + 1); + + auto y_minus_x = y_scaled(k) - x_proxy(k); + static_assert(std::is_same_v); + EXPECT_EQ(y_minus_x, real_t(k) - 1); + + auto minus_y = -y_scaled(k); + static_assert(std::is_same_v); + EXPECT_EQ(minus_y, -2 * real_t(k) - 10); + + auto minus_x = -x_proxy(k); + static_assert(std::is_same_v); + EXPECT_EQ(minus_x, -real_t(k) - 11); + } + } + +#if defined(__cpp_lib_atomic_ref) + TEST(mixed_accessors, mdspan_atomic_double) + { + using real_t = float; + using scalar_t = real_t; + using extents_t = dextents; + using vector_t = mdspan; + + constexpr std::size_t vectorSize(5); + constexpr std::size_t storageSize = 2 * vectorSize; + std::vector storage(storageSize); + + vector_t x(storage.data(), vectorSize); + vector_t y(storage.data() + vectorSize, vectorSize); + + for (std::size_t k = 0; k < vectorSize; ++k) { + const scalar_t x_k(real_t(k) + 5.0f); + const scalar_t y_k(real_t(k) + 11.0f); + x(k) = x_k; + y(k) = y_k; + } + + const scalar_t alpha = 2.0f; + auto x_scaled = scaled(alpha, x); + mdspan> y_proxy(y.data_handle(), y.mapping()); + for (std::size_t k = 0; k < vectorSize; ++k) { + ASSERT_EQ(x_scaled(k), (alpha * (real_t(k) + 5.0f))); + ASSERT_EQ(y_proxy(k), (real_t(k) + 11.0f)); + + auto y_minus_x = y_proxy(k) - x_scaled(k); + static_assert(std::is_same_v); + const scalar_t y_minus_x_expected = -real_t(k) + 1.0f; + EXPECT_EQ(y_minus_x, y_minus_x_expected); + + auto x_minus_y = x_scaled(k) - y_proxy(k); + static_assert(std::is_same_v); + const scalar_t x_minus_y_expected = real_t(k) - 1.0f; + EXPECT_EQ(x_minus_y, x_minus_y_expected); + + auto minus_y = -y_proxy(k); + static_assert(std::is_same_v); + const scalar_t minus_y_expected(-real_t(k) - 11.0f); + EXPECT_EQ(minus_y, minus_y_expected); + + auto minus_x = -x_scaled(k); + static_assert(std::is_same_v); + const scalar_t minus_x_expected(-2.0f * real_t(k) - 10.0f); + EXPECT_EQ(minus_x, minus_x_expected); + } + } +#endif // __cpp_lib_atomic_ref +} // namespace (anonymous) From fc07855adcf2c0fafe0dc9eb8833c5707269ccef Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Fri, 28 Jul 2023 22:25:55 +0800 Subject: [PATCH 14/15] Add test mixing conjugated & scaled --- tests/native/mixed_accessors.cpp | 57 ++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/tests/native/mixed_accessors.cpp b/tests/native/mixed_accessors.cpp index 9a1ae307..95edc2f5 100644 --- a/tests/native/mixed_accessors.cpp +++ b/tests/native/mixed_accessors.cpp @@ -109,9 +109,10 @@ struct atomic_accessor { #endif // __cpp_lib_atomic_ref namespace { + using std::experimental::linalg::conjugated; using std::experimental::linalg::scaled; - TEST(mixed_accessors, mdspan_int) + TEST(mixed_accessors, mdspan_scaled_and_my_proxy) { using real_t = int; using scalar_t = int; @@ -158,7 +159,7 @@ namespace { } #if defined(__cpp_lib_atomic_ref) - TEST(mixed_accessors, mdspan_atomic_double) + TEST(mixed_accessors, mdspan_scaled_and_atomic) { using real_t = float; using scalar_t = real_t; @@ -208,4 +209,56 @@ namespace { } } #endif // __cpp_lib_atomic_ref + + TEST(mixed_accessors, mdspan_scaled_and_conjugated) + { + using real_t = float; + using complex_t = std::complex; + using extents_t = dextents; + using real_vector_t = mdspan; + using complex_vector_t = mdspan; + + constexpr std::size_t vector_size(5); + std::vector real_storage(vector_size); + std::vector complex_storage(vector_size); + + real_vector_t x(real_storage.data(), vector_size); + complex_vector_t y(complex_storage.data(), vector_size); + + for (std::size_t k = 0; k < vector_size; ++k) { + const real_t x_k(real_t(k) + 5.0f); + const complex_t y_k(real_t(k) + 11.0f, real_t(k) + 13.0f);; + x(k) = x_k; + y(k) = y_k; + } + + const real_t alpha = 2.0f; + auto x_scaled = scaled(alpha, x); + auto y_conj = conjugated(y); + + for (std::size_t k = 0; k < vector_size; ++k) { + ASSERT_EQ(x_scaled(k), (2.0f * (real_t(k) + 5.0f))); + ASSERT_EQ(y_conj(k), (complex_t(real_t(k) + 11.0f, -real_t(k) - 13.0f))); + + auto y_minus_x = y_conj(k) - x_scaled(k); + static_assert(std::is_same_v); + const complex_t y_minus_x_expected(-real_t(k) + 1.0f, -real_t(k) - 13.0f); + EXPECT_EQ(y_minus_x, y_minus_x_expected); + + auto x_minus_y = x_scaled(k) - y_conj(k); + static_assert(std::is_same_v); + const complex_t x_minus_y_expected(real_t(k) - 1.0f, real_t(k) + 13.0f); + EXPECT_EQ(x_minus_y, x_minus_y_expected); + + auto minus_y = -y_conj(k); + static_assert(std::is_same_v); + const complex_t minus_y_expected(-real_t(k) - 11.0f, real_t(k) + 13.0f); + EXPECT_EQ(minus_y, minus_y_expected); + + auto minus_x = -x_scaled(k); + static_assert(std::is_same_v); + const real_t minus_x_expected(-2.0f * real_t(k) - 10.0f); + EXPECT_EQ(minus_x, minus_x_expected); + } + } } // namespace (anonymous) From fffdc6f82d7f947d03bf7f2da412618d162bf929 Mon Sep 17 00:00:00 2001 From: Mark Hoemmen Date: Thu, 26 Sep 2024 15:57:59 -0600 Subject: [PATCH 15/15] Bring repo in line with Standard * Rename accessor_scaled to scaled_accessor, and accessor_conjugate to conjugated_accessor * Remove proxy references from both accessor types * Add missing conditional explicit to both accessors' constructors * Otherwise bring conjugated_accessor and scaled_accessor in line with the Standard * Fix namespaces where needed * Fix implementation of conj-if-needed, and add implementations (and tests) of real-if-needed and imag-if-needed * Add tests mixing result of scaled with an mdspan whose accessor uses a proxy reference as its reference type. This increases confidence that the proxy-reference-free design works. --- .../__p1673_bits/blas1_vector_abs_sum.hpp | 8 +- .../blas2_matrix_rank_1_update.hpp | 8 +- .../blas2_matrix_rank_2_update.hpp | 2 +- .../blas2_matrix_vector_product.hpp | 8 +- .../__p1673_bits/blas3_matrix_product.hpp | 8 +- .../blas3_matrix_rank_2k_update.hpp | 2 +- .../blas3_matrix_rank_k_update.hpp | 4 +- .../experimental/__p1673_bits/conjugated.hpp | 3 + .../__p1673_bits/imag_if_needed.hpp | 8 +- .../__p1673_bits}/proxy_reference.hpp | 55 +-- .../__p1673_bits/real_if_needed.hpp | 8 +- include/experimental/__p1673_bits/scaled.hpp | 51 +-- tests/native/CMakeLists.txt | 4 +- tests/native/abs_if_needed.cpp | 47 ++- tests/native/conj_if_needed.cpp | 60 ++++ tests/native/imag_if_needed.cpp | 66 ++++ tests/native/mixed_accessors.cpp | 4 +- tests/native/my_numbers.hpp | 60 ++++ tests/native/proxy_refs.cpp | 321 ++++++++++-------- tests/native/real_if_needed.cpp | 66 ++++ tests/native/scaled.cpp | 5 +- tests/native/test_numbers.cpp | 195 ----------- tests/native/test_numbers.hpp | 228 ------------- .../kokkos-kernels/blas1_dot_kk.hpp | 2 +- .../blas2_matrix_rank_1_update.hpp | 2 +- 25 files changed, 522 insertions(+), 703 deletions(-) rename {tests/native => include/experimental/__p1673_bits}/proxy_reference.hpp (91%) create mode 100644 tests/native/conj_if_needed.cpp create mode 100644 tests/native/imag_if_needed.cpp create mode 100644 tests/native/my_numbers.hpp create mode 100644 tests/native/real_if_needed.cpp delete mode 100644 tests/native/test_numbers.cpp delete mode 100644 tests/native/test_numbers.hpp diff --git a/include/experimental/__p1673_bits/blas1_vector_abs_sum.hpp b/include/experimental/__p1673_bits/blas1_vector_abs_sum.hpp index 8deeeb03..f32b0e69 100644 --- a/include/experimental/__p1673_bits/blas1_vector_abs_sum.hpp +++ b/include/experimental/__p1673_bits/blas1_vector_abs_sum.hpp @@ -87,8 +87,8 @@ Scalar vector_abs_sum( using value_type = typename decltype(v)::value_type; using sum_type = decltype(init + - impl::abs_if_needed(impl::real_part(std::declval())) + - impl::abs_if_needed(impl::imag_part(std::declval()))); + impl::abs_if_needed(impl::real_if_needed(std::declval())) + + impl::abs_if_needed(impl::imag_if_needed(std::declval()))); static_assert(std::is_convertible_v); // TODO Implement the Remarks in para 4. @@ -100,8 +100,8 @@ Scalar vector_abs_sum( } else { for (SizeType i = 0; i < numElt; ++i) { - init += impl::abs_if_needed(impl::real_part(v(i))); - init += impl::abs_if_needed(impl::imag_part(v(i))); + init += impl::abs_if_needed(impl::real_if_needed(v(i))); + init += impl::abs_if_needed(impl::imag_if_needed(v(i))); } } diff --git a/include/experimental/__p1673_bits/blas2_matrix_rank_1_update.hpp b/include/experimental/__p1673_bits/blas2_matrix_rank_1_update.hpp index 1d713ba7..1a1fc446 100644 --- a/include/experimental/__p1673_bits/blas2_matrix_rank_1_update.hpp +++ b/include/experimental/__p1673_bits/blas2_matrix_rank_1_update.hpp @@ -534,7 +534,7 @@ void hermitian_matrix_rank_1_update( if constexpr (std::is_same_v) { for (size_type j = 0; j < A.extent(1); ++j) { - A(j,j) = impl::real_part(A(j,j)); + A(j,j) = impl::real_if_needed(A(j,j)); for (size_type i = j; i < A.extent(0); ++i) { A(i,j) += alpha * x(i) * impl::conj_if_needed(x(j)); } @@ -542,7 +542,7 @@ void hermitian_matrix_rank_1_update( } else { for (size_type j = 0; j < A.extent(1); ++j) { - A(j,j) = impl::real_part(A(j,j)); + A(j,j) = impl::real_if_needed(A(j,j)); for (size_type i = 0; i <= j; ++i) { A(i,j) += alpha * x(i) * impl::conj_if_needed(x(j)); } @@ -643,7 +643,7 @@ void hermitian_matrix_rank_1_update( if constexpr (std::is_same_v) { for (size_type j = 0; j < A.extent(1); ++j) { - A(j,j) = impl::real_part(A(j,j)); + A(j,j) = impl::real_if_needed(A(j,j)); for (size_type i = j; i < A.extent(0); ++i) { A(i,j) += x(i) * impl::conj_if_needed(x(j)); } @@ -651,7 +651,7 @@ void hermitian_matrix_rank_1_update( } else { for (size_type j = 0; j < A.extent(1); ++j) { - A(j,j) = impl::real_part(A(j,j)); + A(j,j) = impl::real_if_needed(A(j,j)); for (size_type i = 0; i <= j; ++i) { A(i,j) += x(i) * impl::conj_if_needed(x(j)); } diff --git a/include/experimental/__p1673_bits/blas2_matrix_rank_2_update.hpp b/include/experimental/__p1673_bits/blas2_matrix_rank_2_update.hpp index cae73dde..af4751da 100644 --- a/include/experimental/__p1673_bits/blas2_matrix_rank_2_update.hpp +++ b/include/experimental/__p1673_bits/blas2_matrix_rank_2_update.hpp @@ -217,7 +217,7 @@ void hermitian_matrix_rank_2_update( const size_type i_lower = lower_tri ? j : size_type(0); const size_type i_upper = lower_tri ? A.extent(0) : j+1; - A(j,j) = impl::real_part(A(j,j)); + A(j,j) = impl::real_if_needed(A(j,j)); for (size_type i = i_lower; i < i_upper; ++i) { A(i,j) += x(i) * impl::conj_if_needed(y(j)) + y(i) * impl::conj_if_needed(x(j)); } diff --git a/include/experimental/__p1673_bits/blas2_matrix_vector_product.hpp b/include/experimental/__p1673_bits/blas2_matrix_vector_product.hpp index 441169a2..e0d98205 100644 --- a/include/experimental/__p1673_bits/blas2_matrix_vector_product.hpp +++ b/include/experimental/__p1673_bits/blas2_matrix_vector_product.hpp @@ -767,7 +767,7 @@ void hermitian_matrix_vector_product( if constexpr (std::is_same_v) { for (size_type j = 0; j < A.extent(1); ++j) { - y(j) += impl::real_part(A(j,j)) * x(j); + y(j) += impl::real_if_needed(A(j,j)) * x(j); for (size_type i = j + size_type(1); i < A.extent(0); ++i) { const auto A_ij = A(i,j); y(i) += A_ij * x(j); @@ -782,7 +782,7 @@ void hermitian_matrix_vector_product( y(i) += A_ij * x(j); y(j) += impl::conj_if_needed(A_ij) * x(i); } - y(j) += impl::real_part(A(j,j)) * x(j); + y(j) += impl::real_if_needed(A(j,j)) * x(j); } } } @@ -897,7 +897,7 @@ void hermitian_matrix_vector_product( if constexpr (std::is_same_v) { for (size_type j = 0; j < A.extent(1); ++j) { - z(j) += impl::real_part(A(j,j)) * x(j); + z(j) += impl::real_if_needed(A(j,j)) * x(j); for (size_type i = j + size_type(1); i < A.extent(0); ++i) { const auto A_ij = A(i,j); z(i) += A_ij * x(j); @@ -912,7 +912,7 @@ void hermitian_matrix_vector_product( z(i) += A_ij * x(j); z(j) += impl::conj_if_needed(A_ij) * x(i); } - z(j) += impl::real_part(A(j,j)) * x(j); + z(j) += impl::real_if_needed(A(j,j)) * x(j); } } } diff --git a/include/experimental/__p1673_bits/blas3_matrix_product.hpp b/include/experimental/__p1673_bits/blas3_matrix_product.hpp index 62240699..882044ee 100644 --- a/include/experimental/__p1673_bits/blas3_matrix_product.hpp +++ b/include/experimental/__p1673_bits/blas3_matrix_product.hpp @@ -191,8 +191,8 @@ constexpr bool valid_input_blas_accessor() using def_acc_type = default_accessor; using conj_def_acc_type = conjugated_accessor; - using scal_def_acc_type = accessor_scaled; - using scal_conj_acc_type = accessor_scaled; + using scal_def_acc_type = scaled_accessor; + using scal_conj_acc_type = scaled_accessor; using conj_scal_acc_type = conjugated_accessor; // The two matrices' accessor types need not be the same. @@ -1730,7 +1730,7 @@ void hermitian_matrix_product( for (size_type k = 0; k < i; ++k){ C(i,j) += A(i,k) * B(k,j); } - C(i,j) += impl::real_part(A(i,i)) * B(i,j); + C(i,j) += impl::real_if_needed(A(i,i)) * B(i,j); for (size_type k = i+1; k < A.extent(0); ++k){ C(i,j) += impl::conj_if_needed(A(k,i)) * B(k,j); } @@ -1744,7 +1744,7 @@ void hermitian_matrix_product( for (size_type k = 0; k < i; ++k) { C(i,j) += impl::conj_if_needed(A(k,i)) * B(k,j); } - C(i,j) += impl::real_part(A(i,i)) * B(i,j); + C(i,j) += impl::real_if_needed(A(i,i)) * B(i,j); for (size_type k = i+1; k < A.extent(1); ++k) { C(i,j) += A(i,k) * B(k,j); } diff --git a/include/experimental/__p1673_bits/blas3_matrix_rank_2k_update.hpp b/include/experimental/__p1673_bits/blas3_matrix_rank_2k_update.hpp index 2d578b77..de8dae1b 100644 --- a/include/experimental/__p1673_bits/blas3_matrix_rank_2k_update.hpp +++ b/include/experimental/__p1673_bits/blas3_matrix_rank_2k_update.hpp @@ -211,7 +211,7 @@ void hermitian_matrix_rank_2k_update( for (size_type j = 0; j < C.extent(1); ++j) { const size_type i_lower = lower_tri ? j : size_type(0); const size_type i_upper = lower_tri ? C.extent(0) : j+1; - C(j,j) = impl::real_part(C(j,j)); + C(j,j) = impl::real_if_needed(C(j,j)); for (size_type i = i_lower; i < i_upper; ++i) { for (size_type k = 0; k < A.extent(1); ++k) { C(i,j) += A(i,k) * impl::conj_if_needed(B(j,k)) + B(i,k) * impl::conj_if_needed(A(j,k)); diff --git a/include/experimental/__p1673_bits/blas3_matrix_rank_k_update.hpp b/include/experimental/__p1673_bits/blas3_matrix_rank_k_update.hpp index 7aa6d680..d4f17a99 100644 --- a/include/experimental/__p1673_bits/blas3_matrix_rank_k_update.hpp +++ b/include/experimental/__p1673_bits/blas3_matrix_rank_k_update.hpp @@ -355,7 +355,7 @@ void hermitian_matrix_rank_k_update( for (size_type j = 0; j < C.extent(1); ++j) { const size_type i_lower = lower_tri ? j : size_type(0); const size_type i_upper = lower_tri ? C.extent(0) : j+1; - C(j, j) = impl::real_part(C(j, j)); + C(j, j) = impl::real_if_needed(C(j, j)); for (size_type i = i_lower; i < i_upper; ++i) { for (size_type k = 0; k < A.extent(1); ++k) { C(i, j) += alpha * A(i, k) * impl::conj_if_needed(A(j, k)); @@ -456,7 +456,7 @@ void hermitian_matrix_rank_k_update( using size_type = std::common_type_t; for (size_type j = 0; j < C.extent(1); ++j) { - C(j, j) = impl::real_part(C(j, j)); + C(j, j) = impl::real_if_needed(C(j, j)); const size_type i_lower = lower_tri ? j : size_type(0); const size_type i_upper = lower_tri ? C.extent(0) : j+1; for (size_type i = i_lower; i < i_upper; ++i) { diff --git a/include/experimental/__p1673_bits/conjugated.hpp b/include/experimental/__p1673_bits/conjugated.hpp index 8476ac43..cd502e70 100644 --- a/include/experimental/__p1673_bits/conjugated.hpp +++ b/include/experimental/__p1673_bits/conjugated.hpp @@ -69,6 +69,9 @@ class conjugated_accessor { class OtherNestedAccessor, /* requires */ (std::is_convertible_v) ) +#if defined(__cpp_conditional_explicit) + explicit(!std::is_convertible_v) +#endif constexpr conjugated_accessor(const conjugated_accessor& other) : nested_accessor_(other.nested_accessor()) {} diff --git a/include/experimental/__p1673_bits/imag_if_needed.hpp b/include/experimental/__p1673_bits/imag_if_needed.hpp index c94f4e9d..96ce5d10 100644 --- a/include/experimental/__p1673_bits/imag_if_needed.hpp +++ b/include/experimental/__p1673_bits/imag_if_needed.hpp @@ -46,8 +46,8 @@ #include #include -namespace std { -namespace experimental { +namespace MDSPAN_IMPL_STANDARD_NAMESPACE { +namespace MDSPAN_IMPL_PROPOSED_NAMESPACE { inline namespace __p1673_version_0 { namespace linalg { namespace impl{ @@ -90,7 +90,7 @@ constexpr inline auto imag_if_needed = [](const auto& t) } // end namespace impl } // end namespace linalg } // end inline namespace __p1673_version_0 -} // end namespace experimental -} // end namespace std +} // end namespace MDSPAN_IMPL_PROPOSED_NAMESPACE +} // end namespace MDSPAN_IMPL_STANDARD_NAMESPACE #endif //LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_IMAG_IF_NEEDED_HPP_ diff --git a/tests/native/proxy_reference.hpp b/include/experimental/__p1673_bits/proxy_reference.hpp similarity index 91% rename from tests/native/proxy_reference.hpp rename to include/experimental/__p1673_bits/proxy_reference.hpp index 249ad7a5..593da69f 100644 --- a/tests/native/proxy_reference.hpp +++ b/include/experimental/__p1673_bits/proxy_reference.hpp @@ -43,7 +43,6 @@ #ifndef LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_PROXY_REFERENCE_HPP_ #define LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_PROXY_REFERENCE_HPP_ -#include "experimental/__p1673_bits/conj_if_needed.hpp" #if defined(__cpp_lib_atomic_ref) && defined(LINALG_ENABLE_ATOMIC_REF) # include #endif @@ -67,56 +66,6 @@ template static constexpr bool is_atomic_ref_not_arithmetic_v> = ! std::is_arithmetic_v; #endif -template -T imag_part_impl(const T& t, std::false_type) -{ - return T{}; -} - -template -auto imag_part_impl(const T& t, std::true_type) -{ - if constexpr (std::is_arithmetic_v) { - return T{}; - } else { - return imag(t); - } -} - -template -auto imag_part(const T& t) -{ - return imag_part_impl(t, has_imag{}); -} - -template -T real_part_impl(const T& t, std::false_type) -{ - return t; -} - -template -auto real_part_impl(const T& t, std::true_type) -{ - if constexpr (std::is_arithmetic_v) { - return t; - } else { - return real(t); - } -} - -template -auto real_part(const T& t) -{ - return real_part_impl(t, has_real{}); -} - -// template -// R imag_part(const std::complex& z) -// { -// return std::imag(z); -// } - // A "tag" for identifying the proxy reference types in this proposal. // It's helpful for this tag to be a complete type, so that we can use // it inside proxy_reference (proxy_reference isn't really complete @@ -224,11 +173,11 @@ class proxy_reference : proxy_reference_base { } friend auto real(const derived_type& x) { - return real_part(value_type(static_cast(x))); + return impl::real_if_needed(value_type(static_cast(x))); } friend auto imag(const derived_type& x) { - return imag_part(value_type(static_cast(x))); + return impl::imag_if_needed(value_type(static_cast(x))); } friend auto conj(const derived_type& x) { diff --git a/include/experimental/__p1673_bits/real_if_needed.hpp b/include/experimental/__p1673_bits/real_if_needed.hpp index 9fb16fe1..70b42035 100644 --- a/include/experimental/__p1673_bits/real_if_needed.hpp +++ b/include/experimental/__p1673_bits/real_if_needed.hpp @@ -46,8 +46,8 @@ #include #include -namespace std { -namespace experimental { +namespace MDSPAN_IMPL_STANDARD_NAMESPACE { +namespace MDSPAN_IMPL_PROPOSED_NAMESPACE { inline namespace __p1673_version_0 { namespace linalg { namespace impl{ @@ -90,7 +90,7 @@ constexpr inline auto real_if_needed = [](const auto& t) } // end namespace impl } // end namespace linalg } // end inline namespace __p1673_version_0 -} // end namespace experimental -} // end namespace std +} // end namespace MDSPAN_IMPL_PROPOSED_NAMESPACE +} // end namespace MDSPAN_IMPL_STANDARD_NAMESPACE #endif //LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_REAL_IF_NEEDED_HPP_ diff --git a/include/experimental/__p1673_bits/scaled.hpp b/include/experimental/__p1673_bits/scaled.hpp index c0897117..c9880da2 100644 --- a/include/experimental/__p1673_bits/scaled.hpp +++ b/include/experimental/__p1673_bits/scaled.hpp @@ -50,62 +50,67 @@ namespace MDSPAN_IMPL_PROPOSED_NAMESPACE { inline namespace __p1673_version_0 { namespace linalg { -template +template class scaled_accessor { public: - using element_type = decltype(std::declval() * std::declval()); - using reference = element_type; - using data_handle_type = typename Accessor::data_handle_type; + using element_type = + std::add_const_t() * std::declval())>; + using reference = std::remove_const_t; + using data_handle_type = typename NestedAccessor::data_handle_type; using offset_policy = - scaled_accessor; + scaled_accessor; - scaled_accessor(const ScalingFactor& scaling_factor, const Accessor& accessor) : - scaling_factor_(scaling_factor), - accessor_(accessor) - {} + constexpr scaled_accessor() = default; MDSPAN_TEMPLATE_REQUIRES( class OtherScalingFactor, class OtherNestedAccessor, /* requires */ ( - std::is_constructible_v && + std::is_constructible_v && std::is_constructible_v ) ) - scaled_accessor(const scaled_accessor& other) : +#if defined(__cpp_conditional_explicit) + explicit(!std::is_convertible_v) +#endif + constexpr scaled_accessor(const scaled_accessor& other) : scaling_factor_(other.scaling_factor()), - accessor_(other.nested_accessor()) + nested_accessor_(other.nested_accessor()) + {} + + constexpr scaled_accessor(const ScalingFactor& s, const NestedAccessor& a) : + scaling_factor_(s), + nested_accessor_(a) {} - reference access(data_handle_type p, ::std::size_t i) const - noexcept(noexcept(scaling_factor_* typename Accessor::element_type(accessor_.access(p, i)))) { - return scaling_factor_ * typename Accessor::element_type(accessor_.access(p, i)); + constexpr reference access(data_handle_type p, ::std::size_t i) const { + return scaling_factor_ * typename NestedAccessor::element_type(nested_accessor_.access(p, i)); } typename offset_policy::data_handle_type - offset(data_handle_type p, ::std::size_t i) const noexcept { - return accessor_.offset(p, i); + constexpr offset(data_handle_type p, ::std::size_t i) const { + return nested_accessor_.offset(p, i); } - Accessor nested_accessor() const { - return accessor_; + constexpr NestedAccessor nested_accessor() const noexcept { + return nested_accessor_; } - ScalingFactor scaling_factor() const { + constexpr ScalingFactor scaling_factor() const noexcept { return scaling_factor_; } private: ScalingFactor scaling_factor_; - Accessor accessor_; + NestedAccessor nested_accessor_; }; namespace impl { template + class NestedAccessor> using scaled_element_type = - std::add_const_t::element_type>; + std::add_const_t::element_type>; } // namespace impl diff --git a/tests/native/CMakeLists.txt b/tests/native/CMakeLists.txt index 9427ebb9..e8275aa2 100644 --- a/tests/native/CMakeLists.txt +++ b/tests/native/CMakeLists.txt @@ -15,6 +15,7 @@ endmacro() linalg_add_test(abs_if_needed) linalg_add_test(abs_sum) linalg_add_test(add) +linalg_add_test(conj_if_needed) linalg_add_test(conjugate_transposed) linalg_add_test(conjugated) linalg_add_test(copy) @@ -27,17 +28,18 @@ linalg_add_test(hemm) linalg_add_test(herk) linalg_add_test(her) linalg_add_test(idx_abs_max) +linalg_add_test(imag_if_needed) linalg_add_test(iterator) linalg_add_test(matrix_inf_norm) linalg_add_test(matrix_one_norm) linalg_add_test(mixed_accessors) linalg_add_test(norm2) linalg_add_test(proxy_refs) +linalg_add_test(real_if_needed) linalg_add_test(scale) linalg_add_test(scaled) linalg_add_test(swap) linalg_add_test(symm) -linalg_add_test(test_numbers) linalg_add_test(syr) linalg_add_test(syrk) linalg_add_test(transposed) diff --git a/tests/native/abs_if_needed.cpp b/tests/native/abs_if_needed.cpp index 9e61a8c4..1fd305ed 100644 --- a/tests/native/abs_if_needed.cpp +++ b/tests/native/abs_if_needed.cpp @@ -1,20 +1,4 @@ -#include "./gtest_fixtures.hpp" - -namespace TestLinearAlgebra { - -class MyReal { -public: - MyReal() = default; - explicit MyReal(double value) : value_(value) {} - double value() const { return value_; } - - friend MyReal abs(MyReal x) { return MyReal{std::abs(x.value())}; } - -private: - double value_ = 0.0; -}; - -} // namespace TestLinearAlgebra +#include "./my_numbers.hpp" namespace { TEST(impl_abs_if_needed, arithmetic_types) { @@ -95,4 +79,33 @@ namespace { } } + TEST(impl_abs_if_needed, std_complex) { + { + auto input = std::complex(-3.0, 4.0); + auto result = LinearAlgebra::impl::abs_if_needed(input); + static_assert(std::is_same_v); + EXPECT_EQ(result, 5.0); + } + { + auto input = std::complex(0.0f, 2.0f); + auto result = LinearAlgebra::impl::abs_if_needed(input); + static_assert(std::is_same_v); + EXPECT_EQ(result, 2.0f); + } + } + + TEST(impl_abs_if_needed, custom_complex) { + { + auto input = TestLinearAlgebra::MyComplex(-3.0, 4.0); + auto result = LinearAlgebra::impl::abs_if_needed(input); + static_assert(std::is_same_v); + EXPECT_EQ(result, 5.0); + } + { + auto input = TestLinearAlgebra::MyComplex(0.0, 2.0); + auto result = LinearAlgebra::impl::abs_if_needed(input); + static_assert(std::is_same_v); + EXPECT_EQ(result, 2.0); + } + } } // end anonymous namespace diff --git a/tests/native/conj_if_needed.cpp b/tests/native/conj_if_needed.cpp new file mode 100644 index 00000000..e981caa7 --- /dev/null +++ b/tests/native/conj_if_needed.cpp @@ -0,0 +1,60 @@ +#include "./my_numbers.hpp" + +namespace { + template + void test_real_conj_if_needed() + { + using LinearAlgebra::impl::conj_if_needed; + + Real z(2.0); + const Real z_conj_expected(2.0); + + auto z_conj = conj_if_needed(z); + static_assert(std::is_same_v); + EXPECT_EQ(z_conj, z_conj_expected); + } + + template + void test_any_complex_conj_if_needed() + { + using LinearAlgebra::impl::conj_if_needed; + + Complex z(2.0, -3.0); + Complex z_orig(2.0, -3.0); + const Complex z_conj_expected(2.0, 3.0); + + auto z_conj = conj_if_needed(z); + static_assert(std::is_same_v); + EXPECT_EQ(z_conj, z_conj_expected); + EXPECT_EQ(z, z_orig); // conj didn't change its input + } + + template + void test_std_complex_conj_if_needed() + { + test_any_complex_conj_if_needed>(); + } + + void test_MyComplex_conj_if_needed() + { + test_any_complex_conj_if_needed(); + } + + TEST(test_numbers, conj_if_needed) + { + test_std_complex_conj_if_needed(); + test_std_complex_conj_if_needed(); + test_std_complex_conj_if_needed(); + + test_MyComplex_conj_if_needed(); + + test_real_conj_if_needed(); + test_real_conj_if_needed(); + test_real_conj_if_needed(); + + test_real_conj_if_needed(); + test_real_conj_if_needed(); + test_real_conj_if_needed(); + test_real_conj_if_needed(); + } +} // end anonymous namespace diff --git a/tests/native/imag_if_needed.cpp b/tests/native/imag_if_needed.cpp new file mode 100644 index 00000000..85b9eb92 --- /dev/null +++ b/tests/native/imag_if_needed.cpp @@ -0,0 +1,66 @@ +#include "./my_numbers.hpp" + +namespace { + template + void test_imag_if_needed_complex() + { + using LinearAlgebra::impl::imag_if_needed; + std::complex z{R(3.0), R(4.0)}; + auto z_imag = imag_if_needed(z); + EXPECT_EQ(z_imag, R(4.0)); + static_assert(std::is_same_v); + } + template + void test_imag_if_needed_floating_point() + { + using LinearAlgebra::impl::imag_if_needed; + T x = 9.0; + auto x_imag = imag_if_needed(x); + EXPECT_EQ(x_imag, T(0.0)); + static_assert(std::is_same_v); + } + template + void test_imag_if_needed_integral() + { + using LinearAlgebra::impl::imag_if_needed; + T x = 3; + auto x_imag = imag_if_needed(x); + EXPECT_EQ(x_imag, T(0)); + static_assert(std::is_same_v); + } + + TEST(test_numbers, imag_if_needed) + { + test_imag_if_needed_complex(); + test_imag_if_needed_complex(); + test_imag_if_needed_complex(); + + test_imag_if_needed_floating_point(); + test_imag_if_needed_floating_point(); + test_imag_if_needed_floating_point(); + + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + + { + using LinearAlgebra::impl::imag_if_needed; + TestLinearAlgebra::MyComplex z{3.0, 4.0}; + auto z_imag = imag_if_needed(z); + EXPECT_EQ(z_imag, 4.0); + static_assert(std::is_same_v); + } + { + using LinearAlgebra::impl::imag_if_needed; + TestLinearAlgebra::MyReal x{3.0}; + auto x_imag = imag_if_needed(x); + EXPECT_EQ(x_imag, TestLinearAlgebra::MyReal{}); + static_assert(std::is_same_v); + } + } +} // end anonymous namespace diff --git a/tests/native/mixed_accessors.cpp b/tests/native/mixed_accessors.cpp index 95edc2f5..0ab25f44 100644 --- a/tests/native/mixed_accessors.cpp +++ b/tests/native/mixed_accessors.cpp @@ -109,8 +109,8 @@ struct atomic_accessor { #endif // __cpp_lib_atomic_ref namespace { - using std::experimental::linalg::conjugated; - using std::experimental::linalg::scaled; + using LinearAlgebra::conjugated; + using LinearAlgebra::scaled; TEST(mixed_accessors, mdspan_scaled_and_my_proxy) { diff --git a/tests/native/my_numbers.hpp b/tests/native/my_numbers.hpp new file mode 100644 index 00000000..db3a046e --- /dev/null +++ b/tests/native/my_numbers.hpp @@ -0,0 +1,60 @@ +#ifndef LINALG_TESTS_NATIVE_MY_NUMBERS_HPP +#define LINALG_TESTS_NATIVE_MY_NUMBERS_HPP + +#include "./gtest_fixtures.hpp" + +namespace TestLinearAlgebra { + +class MyReal { +public: + MyReal() = default; + explicit MyReal(double value) : value_(value) {} + double value() const { return value_; } + + friend MyReal abs(MyReal x) { return MyReal{std::abs(x.value())}; } + + friend bool operator==(MyReal x, MyReal y) { + return x.value() == y.value(); + } + +private: + double value_ = 0.0; +}; + +class MyComplex { +private: + double real_ = 0.0; + double imag_ = 0.0; + +public: + MyComplex() = default; + MyComplex(double re, double im) : real_(re), imag_(im) {} + + friend double real(MyComplex z) { + return z.real_; + } + + friend double imag(MyComplex z) { + return z.imag_; + } + + friend double abs(MyComplex z) { + return std::sqrt(z.real_ * z.real_ + z.imag_ * z.imag_); + } + + friend MyComplex conj(MyComplex z) { + return {z.real_, -z.imag_}; + } + + std::complex value() const { + return {real_, imag_}; + } + + friend bool operator==(MyComplex x, MyComplex y) { + return x.value() == y.value(); + } +}; + +} // namespace TestLinearAlgebra + +#endif // LINALG_TESTS_NATIVE_MY_NUMBERS_HPP diff --git a/tests/native/proxy_refs.cpp b/tests/native/proxy_refs.cpp index da3a83a2..b8e286a6 100644 --- a/tests/native/proxy_refs.cpp +++ b/tests/native/proxy_refs.cpp @@ -1,6 +1,7 @@ #define P1673_CONJUGATED_SCALAR_ARITHMETIC_OPERATORS_REFERENCE_OVERLOADS 1 #include "./gtest_fixtures.hpp" +#include "experimental/__p1673_bits/proxy_reference.hpp" /////////////////////////////////////////////////////////// // Custom real number type for tests @@ -18,151 +19,169 @@ struct FakeRealNumber { } #endif }; -// Non-arithmetic types need a definition of conj, -// else conjugated_scalar won't compile with them. -FakeRealNumber conj(const FakeRealNumber& x) { return x; } // Custom complex number type -struct FakeComplex { - double real; - double imag; +class FakeComplex { +private: + double real_ = 0.0; + double imag_ = 0.0; + +public: + FakeComplex() = default; + FakeComplex(double re, double im) : real_(re), imag_(im) {} + + friend double real(FakeComplex z) { + return z.real_; + } + + friend double imag(FakeComplex z) { + return z.imag_; + } + + friend double abs(FakeComplex z) { + return std::sqrt(z.real_ * z.real_ + z.imag_ * z.imag_); + } + + friend FakeComplex conj(FakeComplex z) { + return {z.real_, -z.imag_}; + } #ifdef __cpp_impl_three_way_comparison - bool operator==(const FakeComplex&) const = default; + bool operator==(const FakeComplex&) const = default; #else friend bool operator==(const FakeComplex& x, const FakeComplex& y) { - return x.real == y.real && x.imag == y.imag; + return x.real_ == y.real_ && x.imag_ == y.imag_; } #endif - constexpr FakeComplex& operator+=(const FakeComplex& other) - { - real += other.real; - imag += other.imag; - return *this; - } - constexpr FakeComplex& operator-=(const FakeComplex& other) - { - real -= other.real; - imag -= other.imag; - return *this; - } - constexpr FakeComplex& operator*=(const FakeComplex& other) - { - real = real * other.real - imag * other.imag; - imag = imag * other.real + real * other.imag; - return *this; - } - constexpr FakeComplex& operator/=(const FakeComplex& other) - { - // just for illustration; please don't implement it this way. - const auto other_mag = other.real * other.real + other.imag * other.imag; - real = (real * other.real + imag * other.imag) / other_mag; - imag = (imag * other.real - real * other.imag) / other_mag; - return *this; - } + constexpr FakeComplex& operator+=(const FakeComplex& other) + { + real_ += other.real_; + imag_ += other.imag_; + return *this; + } + constexpr FakeComplex& operator-=(const FakeComplex& other) + { + real_ -= other.real_; + imag_ -= other.imag_; + return *this; + } + constexpr FakeComplex& operator*=(const FakeComplex& other) + { + real_ = real_ * other.real_ - imag_ * other.imag_; + imag_ = imag_ * other.real_ + real_ * other.imag_; + return *this; + } + constexpr FakeComplex& operator/=(const FakeComplex& other) + { + // just for illustration; please don't implement it this way. + const auto other_mag = other.real_ * other.real_ + other.imag_ * other.imag_; + real_ = (real_ * other.real_ + imag_ * other.imag_) / other_mag; + imag_ = (imag_ * other.real_ - real_ * other.imag_) / other_mag; + return *this; + } - constexpr FakeComplex& operator+=(const double other) - { - real += other; - return *this; - } - constexpr FakeComplex& operator-=(const double other) - { - real -= other; - return *this; - } - constexpr FakeComplex& operator*=(const double other) - { - real *= other; - imag *= other; - return *this; - } - constexpr FakeComplex& operator/=(const double other) - { - real /= other; - imag /= other; - return *this; - } + constexpr FakeComplex& operator+=(const double other) + { + real_ += other; + return *this; + } + constexpr FakeComplex& operator-=(const double other) + { + real_ -= other; + return *this; + } + constexpr FakeComplex& operator*=(const double other) + { + real_ *= other; + imag_ *= other; + return *this; + } + constexpr FakeComplex& operator/=(const double other) + { + real_ /= other; + imag_ /= other; + return *this; + } }; // Unary operators FakeComplex operator+( const FakeComplex& val ) { - return val; + return val; } FakeComplex operator-( const FakeComplex& val ) { - return {-val.real, -val.imag}; + return {-real(val), -imag(val)}; } // Binary homogeneous operators FakeComplex operator+(const FakeComplex& z, const FakeComplex& w) { - return {z.real + w.real, z.imag + w.imag}; + return {real(z) + real(w), imag(z) + imag(w)}; } FakeComplex operator-(const FakeComplex& z, const FakeComplex& w) { - return {z.real - w.real, z.imag - w.imag}; + return {real(z) - real(w), imag(z) - imag(w)}; } FakeComplex operator*(const FakeComplex& z, const FakeComplex& w) { - return {z.real * w.real - z.imag * w.imag, - z.imag * w.real + z.real * w.imag}; + return {real(z) * real(w) - imag(z) * imag(w), + imag(z) * real(w) + real(z) * imag(w)}; } FakeComplex operator/(const FakeComplex& z, const FakeComplex& w) { - // just for illustration; please don't implement it this way. - const auto w_mag = w.real * w.real + w.imag * w.imag; - return {(z.real * w.real + z.imag * w.imag) / w_mag, - (z.imag * w.real - z.real * w.imag) / w_mag}; + // just for illustration; please don't implement it this way. + const auto w_mag = real(w) * real(w) + imag(w) * imag(w); + return {(real(z) * real(w) + imag(z) * imag(w)) / w_mag, + (imag(z) * real(w) - real(z) * imag(w)) / w_mag}; } // Binary (complex,real) operators FakeComplex operator+(const FakeComplex& z, const double w) { - return {z.real + w, z.imag}; + return {real(z) + w, imag(z)}; } FakeComplex operator-(const FakeComplex& z, const double w) { - return {z.real - w, z.imag}; + return {real(z) - w, imag(z)}; } FakeComplex operator*(const FakeComplex& z, const double w) { - return {z.real * w, z.imag * w}; + return {real(z) * w, imag(z) * w}; } FakeComplex operator/(const FakeComplex& z, const double w) { - return {z.real / w, z.imag / w}; + return {real(z) / w, imag(z) / w}; } // Binary (real,complex) operators FakeComplex operator+(const double z, const FakeComplex& w) { - return {z + w.real, z + w.imag}; + return {z + real(w), z + imag(w)}; } FakeComplex operator-(const double z, const FakeComplex& w) { - return {z - w.real, -w.imag}; + return {z - real(w), -imag(w)}; } FakeComplex operator*(const double z, const FakeComplex& w) { - return {z * w.real, z * w.imag}; + return {z * real(w), z * imag(w)}; } FakeComplex operator/(const double z, const FakeComplex& w) { - // just for illustration; please don't implement it this way. - const auto w_mag = w.real * w.real + w.imag * w.imag; - return { - (z * w.real) / w_mag, - (-(z * w.imag)) / w_mag - }; + // just for illustration; please don't implement it this way. + const auto w_mag = real(w) * real(w) + imag(w) * imag(w); + return { + (z * real(w)) / w_mag, + (-(z * imag(w))) / w_mag + }; } // Specialize test helper traits (P1673 does NOT need these) @@ -199,7 +218,7 @@ template void test_complex_conj_if_needed() { using LinearAlgebra::impl::conj_if_needed; - + std::complex z(2.0, -3.0); const std::complex z_conj_expected(2.0, 3.0); @@ -235,7 +254,7 @@ void test_conjugated_scalar_from_reference(Reference zd, Value zd_orig) { using test_helpers::is_atomic_ref_not_arithmetic_v; using LinearAlgebra::impl::conj_if_needed; - using LinearAlgebra::conjugated_scalar; + using LinearAlgebra::conjugated_scalar; using value_type = typename std::remove_cv_t; #ifdef P1673_CONJUGATED_SCALAR_ARITHMETIC_OPERATORS_REFERENCE_OVERLOADS @@ -279,7 +298,7 @@ void test_conjugated_scalar_from_reference(Reference zd, Value zd_orig) value_type left_mul_result = cszd * zd; value_type left_mul_result_expected = conj_if_needed(zd_orig) * zd_orig; EXPECT_EQ(left_mul_result, left_mul_result_expected); - if constexpr (is_atomic_ref_not_arithmetic_v) { + if constexpr (is_atomic_ref_not_arithmetic_v) { EXPECT_EQ(zd.load(), zd_orig); } else { EXPECT_EQ(zd, zd_orig); @@ -289,7 +308,7 @@ void test_conjugated_scalar_from_reference(Reference zd, Value zd_orig) value_type left_div_result = cszd / zd; value_type left_div_result_expected = conj_if_needed(zd_orig) / zd_orig; EXPECT_EQ(left_div_result, left_div_result_expected); - if constexpr (is_atomic_ref_not_arithmetic_v) { + if constexpr (is_atomic_ref_not_arithmetic_v) { EXPECT_EQ(zd.load(), zd_orig); } else { EXPECT_EQ(zd, zd_orig); @@ -312,7 +331,7 @@ void test_conjugated_scalar_from_reference(Reference zd, Value zd_orig) value_type left_sub_result2_expected = conj_if_needed(zd_orig) - get_test_xvalue(value_type{}); EXPECT_EQ(left_sub_result2, left_sub_result2_expected); - if constexpr (is_atomic_ref_not_arithmetic_v) { + if constexpr (is_atomic_ref_not_arithmetic_v) { EXPECT_EQ(zd.load(), zd_orig); } else { EXPECT_EQ(zd, zd_orig); @@ -564,7 +583,7 @@ template void test_arithmetic_conjugated_scalar() { static_assert(std::is_arithmetic_v); - + std::cerr << "test_arithmetic_conjugated_scalar" << std::endl; Value zd_orig{2}; @@ -614,7 +633,7 @@ void test_scaled_scalar_from_reference( { std::cerr << "test_scaled_scalar_from_reference" << std::endl; - using LinearAlgebra::impl::conj_if_needed; + using LinearAlgebra::impl::conj_if_needed; using LinearAlgebra::scaled_scalar; using value_type = typename std::remove_cv_t; constexpr bool is_atomic_ref_not_arithmetic = @@ -902,7 +921,7 @@ void test_two_scaled_scalars_from_reference( << scalingFactorName << ", " << referenceName << ", " << valueName << ">" << std::endl; - using LinearAlgebra::scaled_scalar; + using LinearAlgebra::scaled_scalar; using value_type = typename std::remove_cv_t; constexpr bool is_atomic_ref_not_arithmetic = test_helpers::is_atomic_ref_not_arithmetic_v; @@ -1013,7 +1032,7 @@ void test_arithmetic_scaled_scalar(const char valueName[]) const Value zd2{3}; test_scaled_scalar_from_reference< Value, const Value&, Value>(scalingFactor, zd2, zd2_orig); - + const std::string valueRefName = std::string("const ") + valueName + "&"; test_two_scaled_scalars_from_reference< Value, const Value&, Value>(scalingFactor, zd2, zd2_orig, @@ -1056,131 +1075,131 @@ namespace { } template - void test_imag_part_complex() + void test_imag_if_needed_complex() { - using LinearAlgebra::impl::imag_part; + using LinearAlgebra::impl::imag_if_needed; std::complex z{R(3.0), R(4.0)}; - auto z_imag = imag_part(z); + auto z_imag = imag_if_needed(z); EXPECT_EQ(z_imag, R(4.0)); static_assert(std::is_same_v); } template - void test_imag_part_floating_point() + void test_imag_if_needed_floating_point() { - using LinearAlgebra::impl::imag_part; + using LinearAlgebra::impl::imag_if_needed; T x = 9.0; - auto x_imag = imag_part(x); + auto x_imag = imag_if_needed(x); EXPECT_EQ(x_imag, T(0.0)); static_assert(std::is_same_v); } template - void test_imag_part_integral() + void test_imag_if_needed_integral() { - using LinearAlgebra::impl::imag_part; + using LinearAlgebra::impl::imag_if_needed; T x = 3; - auto x_imag = imag_part(x); + auto x_imag = imag_if_needed(x); EXPECT_EQ(x_imag, T(0)); static_assert(std::is_same_v); } - TEST(proxy_refs, imag_part) + TEST(proxy_refs, imag_if_needed) { - test_imag_part_complex(); - test_imag_part_complex(); - test_imag_part_complex(); - - test_imag_part_floating_point(); - test_imag_part_floating_point(); - test_imag_part_floating_point(); - - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); - test_imag_part_integral(); + test_imag_if_needed_complex(); + test_imag_if_needed_complex(); + test_imag_if_needed_complex(); + + test_imag_if_needed_floating_point(); + test_imag_if_needed_floating_point(); + test_imag_if_needed_floating_point(); + + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); + test_imag_if_needed_integral(); { - using LinearAlgebra::impl::imag_part; + using LinearAlgebra::impl::imag_if_needed; FakeComplex z{3.0, 4.0}; - auto z_imag = imag_part(z); + auto z_imag = imag_if_needed(z); EXPECT_EQ(z_imag, 4.0); - static_assert(std::is_same_v); + static_assert(std::is_same_v); } { - using LinearAlgebra::impl::imag_part; + using LinearAlgebra::impl::imag_if_needed; FakeRealNumber x{3.0}; - auto x_imag = imag_part(x); + auto x_imag = imag_if_needed(x); EXPECT_EQ(x_imag, FakeRealNumber{}); static_assert(std::is_same_v); } } template - void test_real_part_complex() + void test_real_if_needed_complex() { - using LinearAlgebra::impl::real_part; + using LinearAlgebra::impl::real_if_needed; std::complex z{R(3.0), R(4.0)}; - auto z_imag = real_part(z); + auto z_imag = real_if_needed(z); EXPECT_EQ(z_imag, R(3.0)); static_assert(std::is_same_v); } template - void test_real_part_floating_point() + void test_real_if_needed_floating_point() { - using LinearAlgebra::impl::real_part; + using LinearAlgebra::impl::real_if_needed; T x = 9.0; - auto x_imag = real_part(x); + auto x_imag = real_if_needed(x); EXPECT_EQ(x_imag, T(9.0)); static_assert(std::is_same_v); } template - void test_real_part_integral() + void test_real_if_needed_integral() { - using LinearAlgebra::impl::real_part; + using LinearAlgebra::impl::real_if_needed; T x = 3; - auto x_imag = real_part(x); + auto x_imag = real_if_needed(x); EXPECT_EQ(x_imag, T(3)); static_assert(std::is_same_v); } - TEST(proxy_refs, real_part) + TEST(proxy_refs, real_if_needed) { - test_real_part_complex(); - test_real_part_complex(); - test_real_part_complex(); - - test_real_part_floating_point(); - test_real_part_floating_point(); - test_real_part_floating_point(); - - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); - test_real_part_integral(); + test_real_if_needed_complex(); + test_real_if_needed_complex(); + test_real_if_needed_complex(); + + test_real_if_needed_floating_point(); + test_real_if_needed_floating_point(); + test_real_if_needed_floating_point(); + + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); { - using LinearAlgebra::impl::real_part; + using LinearAlgebra::impl::real_if_needed; FakeComplex z{3.0, 4.0}; - auto z_imag = real_part(z); + auto z_imag = real_if_needed(z); EXPECT_EQ(z_imag, 3.0); - static_assert(std::is_same_v); + static_assert(std::is_same_v); } { - using LinearAlgebra::impl::real_part; + using LinearAlgebra::impl::real_if_needed; FakeRealNumber x{3.0}; - auto x_real = real_part(x); + auto x_real = real_if_needed(x); EXPECT_EQ(x_real, FakeRealNumber{3.0}); static_assert(std::is_same_v); } } - + TEST(proxy_refs, conjugated_scalar) { test_complex_conjugated_scalar(); diff --git a/tests/native/real_if_needed.cpp b/tests/native/real_if_needed.cpp new file mode 100644 index 00000000..6175fb4c --- /dev/null +++ b/tests/native/real_if_needed.cpp @@ -0,0 +1,66 @@ +#include "./my_numbers.hpp" + +namespace { + template + void test_real_if_needed_complex() + { + using LinearAlgebra::impl::real_if_needed; + std::complex z{R(3.0), R(4.0)}; + auto z_imag = real_if_needed(z); + EXPECT_EQ(z_imag, R(3.0)); + static_assert(std::is_same_v); + } + template + void test_real_if_needed_floating_point() + { + using LinearAlgebra::impl::real_if_needed; + T x = 9.0; + auto x_imag = real_if_needed(x); + EXPECT_EQ(x_imag, T(9.0)); + static_assert(std::is_same_v); + } + template + void test_real_if_needed_integral() + { + using LinearAlgebra::impl::real_if_needed; + T x = 3; + auto x_imag = real_if_needed(x); + EXPECT_EQ(x_imag, T(3)); + static_assert(std::is_same_v); + } + + TEST(test_numbers, real_if_needed) + { + test_real_if_needed_complex(); + test_real_if_needed_complex(); + test_real_if_needed_complex(); + + test_real_if_needed_floating_point(); + test_real_if_needed_floating_point(); + test_real_if_needed_floating_point(); + + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + test_real_if_needed_integral(); + + { + using LinearAlgebra::impl::real_if_needed; + TestLinearAlgebra::MyComplex z{ 3.0, 4.0 }; + auto z_imag = real_if_needed(z); + EXPECT_EQ(z_imag, 3.0); + static_assert(std::is_same_v); + } + { + using LinearAlgebra::impl::real_if_needed; + TestLinearAlgebra::MyReal x{ 3.0 }; + auto x_real = real_if_needed(x); + EXPECT_EQ(x_real, TestLinearAlgebra::MyReal{ 3.0 }); + static_assert(std::is_same_v); + } + } +} // end anonymous namespace diff --git a/tests/native/scaled.cpp b/tests/native/scaled.cpp index 7c11b369..6361965b 100644 --- a/tests/native/scaled.cpp +++ b/tests/native/scaled.cpp @@ -7,8 +7,7 @@ namespace { template void test_scaled_accessor_element_constification() { - using LinearAlgebra::accessor_scaled; - using LinearAlgebra::scaled_scalar; + using LinearAlgebra::scaled_accessor; using nc_def_acc_type = default_accessor; using c_def_acc_type = @@ -82,7 +81,7 @@ namespace { // Make sure that scaled_accessor compiles { using accessor_t = vector_t::accessor_type; - using LinearAlgebra::accessor_scaled; + using LinearAlgebra::scaled_accessor; using scaled_accessor_t = scaled_accessor; scaled_accessor_t accessor0{scalingFactor, y.accessor()}; diff --git a/tests/native/test_numbers.cpp b/tests/native/test_numbers.cpp deleted file mode 100644 index 4c8e45e5..00000000 --- a/tests/native/test_numbers.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#define MDSPAN_USE_PAREN_OPERATOR 1 -#define P1673_CONJUGATED_SCALAR_ARITHMETIC_OPERATORS_REFERENCE_OVERLOADS 1 - -#include "gtest/gtest.h" -#include "./test_numbers.hpp" -#include - -/////////////////////////////////////////////////////////// -// conj_if_needed tests -/////////////////////////////////////////////////////////// - -namespace { - template - void test_real_conj_if_needed() - { - using std::experimental::linalg::impl::conj_if_needed; - - Real z(2.0); - const Real z_conj_expected(2.0); - - auto z_conj = conj_if_needed(z); - static_assert(std::is_same_v); - EXPECT_EQ(z_conj, z_conj_expected); - } - - template - void test_any_complex_conj_if_needed() - { - using std::experimental::linalg::impl::conj_if_needed; - - Complex z(2.0, -3.0); - Complex z_orig(2.0, -3.0); - const Complex z_conj_expected(2.0, 3.0); - - auto z_conj = conj_if_needed(z); - static_assert(std::is_same_v); - EXPECT_EQ(z_conj, z_conj_expected); - EXPECT_EQ(z, z_orig); // conj didn't change its input - } - - template - void test_std_complex_conj_if_needed() - { - test_any_complex_conj_if_needed>(); - } - - void test_FakeComplex_conj_if_needed() - { - test_any_complex_conj_if_needed(); - } - - TEST(test_numbers, conj_if_needed) - { - test_std_complex_conj_if_needed(); - test_std_complex_conj_if_needed(); - test_std_complex_conj_if_needed(); - - test_FakeComplex_conj_if_needed(); - - test_real_conj_if_needed(); - test_real_conj_if_needed(); - test_real_conj_if_needed(); - - test_real_conj_if_needed(); - test_real_conj_if_needed(); - test_real_conj_if_needed(); - test_real_conj_if_needed(); - } - - template - void test_imag_if_needed_complex() - { - using std::experimental::linalg::impl::imag_if_needed; - std::complex z{R(3.0), R(4.0)}; - auto z_imag = imag_if_needed(z); - EXPECT_EQ(z_imag, R(4.0)); - static_assert(std::is_same_v); - } - template - void test_imag_if_needed_floating_point() - { - using std::experimental::linalg::impl::imag_if_needed; - T x = 9.0; - auto x_imag = imag_if_needed(x); - EXPECT_EQ(x_imag, T(0.0)); - static_assert(std::is_same_v); - } - template - void test_imag_if_needed_integral() - { - using std::experimental::linalg::impl::imag_if_needed; - T x = 3; - auto x_imag = imag_if_needed(x); - EXPECT_EQ(x_imag, T(0)); - static_assert(std::is_same_v); - } - - TEST(test_numbers, imag_if_needed) - { - test_imag_if_needed_complex(); - test_imag_if_needed_complex(); - test_imag_if_needed_complex(); - - test_imag_if_needed_floating_point(); - test_imag_if_needed_floating_point(); - test_imag_if_needed_floating_point(); - - test_imag_if_needed_integral(); - test_imag_if_needed_integral(); - test_imag_if_needed_integral(); - test_imag_if_needed_integral(); - test_imag_if_needed_integral(); - test_imag_if_needed_integral(); - test_imag_if_needed_integral(); - test_imag_if_needed_integral(); - - { - using std::experimental::linalg::impl::imag_if_needed; - FakeComplex z{3.0, 4.0}; - auto z_imag = imag_if_needed(z); - EXPECT_EQ(z_imag, 4.0); - static_assert(std::is_same_v); - } - { - using std::experimental::linalg::impl::imag_if_needed; - FakeRealNumber x{3.0}; - auto x_imag = imag_if_needed(x); - EXPECT_EQ(x_imag, FakeRealNumber{}); - static_assert(std::is_same_v); - } - } - - template - void test_real_if_needed_complex() - { - using std::experimental::linalg::impl::real_if_needed; - std::complex z{R(3.0), R(4.0)}; - auto z_imag = real_if_needed(z); - EXPECT_EQ(z_imag, R(3.0)); - static_assert(std::is_same_v); - } - template - void test_real_if_needed_floating_point() - { - using std::experimental::linalg::impl::real_if_needed; - T x = 9.0; - auto x_imag = real_if_needed(x); - EXPECT_EQ(x_imag, T(9.0)); - static_assert(std::is_same_v); - } - template - void test_real_if_needed_integral() - { - using std::experimental::linalg::impl::real_if_needed; - T x = 3; - auto x_imag = real_if_needed(x); - EXPECT_EQ(x_imag, T(3)); - static_assert(std::is_same_v); - } - - TEST(test_numbers, real_if_needed) - { - test_real_if_needed_complex(); - test_real_if_needed_complex(); - test_real_if_needed_complex(); - - test_real_if_needed_floating_point(); - test_real_if_needed_floating_point(); - test_real_if_needed_floating_point(); - - test_real_if_needed_integral(); - test_real_if_needed_integral(); - test_real_if_needed_integral(); - test_real_if_needed_integral(); - test_real_if_needed_integral(); - test_real_if_needed_integral(); - test_real_if_needed_integral(); - test_real_if_needed_integral(); - - { - using std::experimental::linalg::impl::real_if_needed; - FakeComplex z{ 3.0, 4.0 }; - auto z_imag = real_if_needed(z); - EXPECT_EQ(z_imag, 3.0); - static_assert(std::is_same_v); - } - { - using std::experimental::linalg::impl::real_if_needed; - FakeRealNumber x{ 3.0 }; - auto x_real = real_if_needed(x); - EXPECT_EQ(x_real, FakeRealNumber{ 3.0 }); - static_assert(std::is_same_v); - } - } -} // namespace (anonymous) diff --git a/tests/native/test_numbers.hpp b/tests/native/test_numbers.hpp deleted file mode 100644 index 9d56d145..00000000 --- a/tests/native/test_numbers.hpp +++ /dev/null @@ -1,228 +0,0 @@ -/* -//@HEADER -// ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2019) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, -// the U.S. Government retains certain rights in this software. // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the Corporation nor the names of the -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// -// ************************************************************************ -//@HEADER -*/ - -#ifndef LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_TEST_NUMBERS_HPP_ -#define LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_TEST_NUMBERS_HPP_ - -#define P1673_CONJUGATED_SCALAR_ARITHMETIC_OPERATORS_REFERENCE_OVERLOADS 1 - -#include "gtest/gtest.h" -#include - -/////////////////////////////////////////////////////////// -// Custom real number type for tests -/////////////////////////////////////////////////////////// - -struct FakeRealNumber { - float value; - -#ifdef __cpp_impl_three_way_comparison - bool operator==(const FakeRealNumber&) const = default; -#else - friend bool operator==(const FakeRealNumber& x, const FakeRealNumber& y) - { - return x.value == y.value; - } -#endif -}; - -// conj_if_needed assumes that FakeRealNumber is a real number, -// because it doesn't have an ADL-accessible definition of conj. -FakeRealNumber conj(const FakeRealNumber& x) { return x; } - -/////////////////////////////////////////////////////////// -// Custom real number type for tests -/////////////////////////////////////////////////////////// - -struct FakeComplex { - double real; - double imag; - -#ifdef __cpp_impl_three_way_comparison - bool operator==(const FakeComplex&) const = default; -#else - friend bool operator==(const FakeComplex& x, const FakeComplex& y) - { - return x.real == y.real && x.imag == y.imag; - } -#endif - - constexpr FakeComplex& operator+=(const FakeComplex& other) - { - real += other.real; - imag += other.imag; - return *this; - } - constexpr FakeComplex& operator-=(const FakeComplex& other) - { - real -= other.real; - imag -= other.imag; - return *this; - } - constexpr FakeComplex& operator*=(const FakeComplex& other) - { - real = real * other.real - imag * other.imag; - imag = imag * other.real + real * other.imag; - return *this; - } - constexpr FakeComplex& operator/=(const FakeComplex& other) - { - // just for illustration; please don't implement it this way. - const auto other_mag = other.real * other.real + other.imag * other.imag; - real = (real * other.real + imag * other.imag) / other_mag; - imag = (imag * other.real - real * other.imag) / other_mag; - return *this; - } - - constexpr FakeComplex& operator+=(const double other) - { - real += other; - return *this; - } - constexpr FakeComplex& operator-=(const double other) - { - real -= other; - return *this; - } - constexpr FakeComplex& operator*=(const double other) - { - real *= other; - imag *= other; - return *this; - } - constexpr FakeComplex& operator/=(const double other) - { - real /= other; - imag /= other; - return *this; - } -}; - -// Unary operators - -FakeComplex operator+(const FakeComplex& val) -{ - return val; -} -FakeComplex operator-(const FakeComplex& val) -{ - return { -val.real, -val.imag }; -} - -// Binary homogeneous operators - -FakeComplex operator+(const FakeComplex& z, const FakeComplex& w) -{ - return { z.real + w.real, z.imag + w.imag }; -} -FakeComplex operator-(const FakeComplex& z, const FakeComplex& w) -{ - return { z.real - w.real, z.imag - w.imag }; -} -FakeComplex operator*(const FakeComplex& z, const FakeComplex& w) -{ - return { z.real * w.real - z.imag * w.imag, - z.imag * w.real + z.real * w.imag }; -} -FakeComplex operator/(const FakeComplex& z, const FakeComplex& w) -{ - // just for illustration; please don't implement it this way. - const auto w_mag = w.real * w.real + w.imag * w.imag; - return { (z.real * w.real + z.imag * w.imag) / w_mag, - (z.imag * w.real - z.real * w.imag) / w_mag }; -} - -// Binary (complex,real) operators - -FakeComplex operator+(const FakeComplex& z, const double w) -{ - return { z.real + w, z.imag }; -} -FakeComplex operator-(const FakeComplex& z, const double w) -{ - return { z.real - w, z.imag }; -} -FakeComplex operator*(const FakeComplex& z, const double w) -{ - return { z.real * w, z.imag * w }; -} -FakeComplex operator/(const FakeComplex& z, const double w) -{ - return { z.real / w, z.imag / w }; -} - -// Binary (real,complex) operators - -FakeComplex operator+(const double z, const FakeComplex& w) -{ - return { z + w.real, z + w.imag }; -} -FakeComplex operator-(const double z, const FakeComplex& w) -{ - return { z - w.real, -w.imag }; -} -FakeComplex operator*(const double z, const FakeComplex& w) -{ - return { z * w.real, z * w.imag }; -} -FakeComplex operator/(const double z, const FakeComplex& w) -{ - // just for illustration; please don't implement it this way. - const auto w_mag = w.real * w.real + w.imag * w.imag; - return { - (z * w.real) / w_mag, - (-(z * w.imag)) / w_mag - }; -} - -// conj_if_needed knows that FakeComplex is a complex number -// because it has this ADL-findable conj function. -// Ditto for abs, real, and imag below. -FakeComplex conj(const FakeComplex& z) { return { z.real, -z.imag }; } - -auto abs(const FakeComplex& z) { return sqrt(z.real * z.real + z.imag * z.imag); } - -auto real(const FakeComplex& z) { return z.real; } - -auto imag(const FakeComplex& z) { return z.imag; } - -#endif //LINALG_INCLUDE_EXPERIMENTAL___P1673_BITS_TEST_NUMBERS_HPP_ diff --git a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas1_dot_kk.hpp b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas1_dot_kk.hpp index a619fa9e..4b1b9885 100644 --- a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas1_dot_kk.hpp +++ b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas1_dot_kk.hpp @@ -80,7 +80,7 @@ Scalar dot(kokkos_exec, ElementType_x, std::experimental::extents, Layout_x, - std::experimental::linalg::conjugate_accessor< + std::experimental::linalg::conjugated_accessor< std::experimental::default_accessor, ElementType_x > > x, diff --git a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_matrix_rank_1_update.hpp b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_matrix_rank_1_update.hpp index 9ed0a32c..5df665fa 100644 --- a/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_matrix_rank_1_update.hpp +++ b/tpl-implementations/include/experimental/__p1673_bits/kokkos-kernels/blas2_matrix_rank_1_update.hpp @@ -120,7 +120,7 @@ void matrix_rank_1_update(kokkos_exec &&/* exec */, std::experimental::mdspan, Layout_x, std::experimental::default_accessor> x, std::experimental::mdspan, Layout_y, - std::experimental::linalg::conjugate_accessor< + std::experimental::linalg::conjugated_accessor< std::experimental::default_accessor, ElementType_y>> y, std::experimental::mdspan, Layout_A, std::experimental::default_accessor> A)