diff --git a/core/matrix/dense.cpp b/core/matrix/dense.cpp index 398b5192035..2cb02fb4361 100644 --- a/core/matrix/dense.cpp +++ b/core/matrix/dense.cpp @@ -812,6 +812,17 @@ Dense::make_complex() const } +template +void Dense::make_complex(Dense> *result) const +{ + auto exec = this->get_executor(); + + GKO_ASSERT_EQUAL_DIMENSIONS(this, result); + + exec->run(dense::make_make_complex(this, result)); +} + + template std::unique_ptr::absolute_type> Dense::get_real() const @@ -826,6 +837,17 @@ Dense::get_real() const } +template +void Dense::get_real(Dense> *result) const +{ + auto exec = this->get_executor(); + + GKO_ASSERT_EQUAL_DIMENSIONS(this, result); + + exec->run(dense::make_get_real(this, result)); +} + + template std::unique_ptr::absolute_type> Dense::get_imag() const @@ -840,6 +862,17 @@ Dense::get_imag() const } +template +void Dense::get_imag(Dense> *result) const +{ + auto exec = this->get_executor(); + + GKO_ASSERT_EQUAL_DIMENSIONS(this, result); + + exec->run(dense::make_get_imag(this, result)); +} + + #define GKO_DECLARE_DENSE_MATRIX(_type) class Dense<_type> GKO_INSTANTIATE_FOR_EACH_VALUE_TYPE(GKO_DECLARE_DENSE_MATRIX); diff --git a/cuda/test/matrix/dense_kernels.cpp b/cuda/test/matrix/dense_kernels.cpp index ea067231ece..823aabe9b2b 100644 --- a/cuda/test/matrix/dense_kernels.cpp +++ b/cuda/test/matrix/dense_kernels.cpp @@ -654,6 +654,19 @@ TEST_F(Dense, MakeComplexIsEquivalentToRef) } +TEST_F(Dense, MakeComplexWithGivenResultIsEquivalentToRef) +{ + set_up_apply_data(); + + auto complex_x = ComplexMtx::create(ref, x->get_size()); + x->make_complex(complex_x.get()); + auto dcomplex_x = ComplexMtx::create(cuda, x->get_size()); + dx->make_complex(dcomplex_x.get()); + + GKO_ASSERT_MTX_NEAR(complex_x, dcomplex_x, 0); +} + + TEST_F(Dense, GetRealIsEquivalentToRef) { set_up_apply_data(); @@ -665,6 +678,19 @@ TEST_F(Dense, GetRealIsEquivalentToRef) } +TEST_F(Dense, GetRealWithGivenResultIsEquivalentToRef) +{ + set_up_apply_data(); + + auto real_x = Mtx::create(ref, x->get_size()); + x->get_real(real_x.get()); + auto dreal_x = Mtx::create(cuda, dx->get_size()); + dx->get_real(dreal_x.get()); + + GKO_ASSERT_MTX_NEAR(real_x, dreal_x, 0); +} + + TEST_F(Dense, GetImagIsEquivalentToRef) { set_up_apply_data(); @@ -676,4 +702,17 @@ TEST_F(Dense, GetImagIsEquivalentToRef) } +TEST_F(Dense, GetImagWithGivenResultIsEquivalentToRef) +{ + set_up_apply_data(); + + auto imag_x = Mtx::create(ref, x->get_size()); + x->get_imag(imag_x.get()); + auto dimag_x = Mtx::create(cuda, dx->get_size()); + dx->get_imag(dimag_x.get()); + + GKO_ASSERT_MTX_NEAR(imag_x, dimag_x, 0); +} + + } // namespace diff --git a/hip/test/matrix/dense_kernels.hip.cpp b/hip/test/matrix/dense_kernels.hip.cpp index 5268e6d1878..a4f4b4e58f1 100644 --- a/hip/test/matrix/dense_kernels.hip.cpp +++ b/hip/test/matrix/dense_kernels.hip.cpp @@ -637,6 +637,19 @@ TEST_F(Dense, MakeComplexIsEquivalentToRef) } +TEST_F(Dense, MakeComplexWithGivenResultIsEquivalentToRef) +{ + set_up_apply_data(); + + auto complex_x = ComplexMtx::create(ref, x->get_size()); + x->make_complex(complex_x.get()); + auto dcomplex_x = ComplexMtx::create(hip, x->get_size()); + dx->make_complex(dcomplex_x.get()); + + GKO_ASSERT_MTX_NEAR(complex_x, dcomplex_x, 0); +} + + TEST_F(Dense, GetRealIsEquivalentToRef) { set_up_apply_data(); @@ -648,6 +661,19 @@ TEST_F(Dense, GetRealIsEquivalentToRef) } +TEST_F(Dense, GetRealWithGivenResultIsEquivalentToRef) +{ + set_up_apply_data(); + + auto real_x = Mtx::create(ref, x->get_size()); + x->get_real(real_x.get()); + auto dreal_x = Mtx::create(hip, dx->get_size()); + dx->get_real(dreal_x.get()); + + GKO_ASSERT_MTX_NEAR(real_x, dreal_x, 0); +} + + TEST_F(Dense, GetImagIsEquivalentToRef) { set_up_apply_data(); @@ -659,4 +685,17 @@ TEST_F(Dense, GetImagIsEquivalentToRef) } +TEST_F(Dense, GetImagWithGivenResultIsEquivalentToRef) +{ + set_up_apply_data(); + + auto imag_x = Mtx::create(ref, x->get_size()); + x->get_imag(imag_x.get()); + auto dimag_x = Mtx::create(hip, dx->get_size()); + dx->get_imag(dimag_x.get()); + + GKO_ASSERT_MTX_NEAR(imag_x, dimag_x, 0); +} + + } // namespace diff --git a/include/ginkgo/core/matrix/dense.hpp b/include/ginkgo/core/matrix/dense.hpp index b7359599104..7bb439afc34 100644 --- a/include/ginkgo/core/matrix/dense.hpp +++ b/include/ginkgo/core/matrix/dense.hpp @@ -262,18 +262,36 @@ class Dense */ std::unique_ptr make_complex() const; + /** + * Writes a complex copy of the original matrix to a given complex matrix. + * If the original matrix was real, the imaginary part of the result will + * be zero. + */ + void make_complex(Dense> *result) const; + /** * Creates a new real matrix and extracts the real part of the original * matrix into that. */ std::unique_ptr get_real() const; + /** + * Extracts the real part of the original matrix into a given real matrix. + */ + void get_real(Dense> *result) const; + /** * Creates a new real matrix and extracts the imaginary part of the * original matrix into that. */ std::unique_ptr get_imag() const; + /** + * Extracts the imaginary part of the original matrix into a given real + * matrix. + */ + void get_imag(Dense> *result) const; + /** * Returns a pointer to the array of values of the matrix. * diff --git a/omp/test/matrix/dense_kernels.cpp b/omp/test/matrix/dense_kernels.cpp index fc5089fcf8a..cf2d975c2ef 100644 --- a/omp/test/matrix/dense_kernels.cpp +++ b/omp/test/matrix/dense_kernels.cpp @@ -769,6 +769,19 @@ TEST_F(Dense, MakeComplexIsEquivalentToRef) } +TEST_F(Dense, MakeComplexWithGivenResultIsEquivalentToRef) +{ + set_up_apply_data(); + + auto complex_x = ComplexMtx::create(ref, x->get_size()); + x->make_complex(complex_x.get()); + auto dcomplex_x = ComplexMtx::create(omp, x->get_size()); + dx->make_complex(dcomplex_x.get()); + + GKO_ASSERT_MTX_NEAR(complex_x, dcomplex_x, 0); +} + + TEST_F(Dense, GetRealIsEquivalentToRef) { set_up_apply_data(); @@ -780,6 +793,19 @@ TEST_F(Dense, GetRealIsEquivalentToRef) } +TEST_F(Dense, GetRealWithGivenResultIsEquivalentToRef) +{ + set_up_apply_data(); + + auto real_x = Mtx::create(ref, x->get_size()); + x->get_real(real_x.get()); + auto dreal_x = Mtx::create(omp, dx->get_size()); + dx->get_real(dreal_x.get()); + + GKO_ASSERT_MTX_NEAR(real_x, dreal_x, 0); +} + + TEST_F(Dense, GetImagIsEquivalentToRef) { set_up_apply_data(); @@ -791,4 +817,17 @@ TEST_F(Dense, GetImagIsEquivalentToRef) } +TEST_F(Dense, GetImagWithGivenResultIsEquivalentToRef) +{ + set_up_apply_data(); + + auto imag_x = Mtx::create(ref, x->get_size()); + x->get_imag(imag_x.get()); + auto dimag_x = Mtx::create(omp, dx->get_size()); + dx->get_imag(dimag_x.get()); + + GKO_ASSERT_MTX_NEAR(imag_x, dimag_x, 0); +} + + } // namespace diff --git a/reference/test/matrix/dense_kernels.cpp b/reference/test/matrix/dense_kernels.cpp index c4eba2fdc9b..b84752911e0 100644 --- a/reference/test/matrix/dense_kernels.cpp +++ b/reference/test/matrix/dense_kernels.cpp @@ -65,6 +65,8 @@ class Dense : public ::testing::Test { protected: using value_type = T; using Mtx = gko::matrix::Dense; + using ComplexMtx = gko::matrix::Dense>; + using RealMtx = gko::matrix::Dense>; Dense() : exec(gko::ReferenceExecutor::create()), mtx1(gko::initialize(4, {{1.0, 2.0, 3.0}, {1.5, 2.5, 3.5}}, @@ -2160,9 +2162,45 @@ TYPED_TEST(Dense, MakeComplex) // {2.1, 3.4, 1.2} // clang-format on - auto abs_mtx = this->mtx5->make_complex(); + auto complex_mtx = this->mtx5->make_complex(); - GKO_ASSERT_MTX_NEAR(abs_mtx, this->mtx5, r::value); + GKO_ASSERT_MTX_NEAR(complex_mtx, this->mtx5, 0); +} + + +TYPED_TEST(Dense, MakeComplexWithGivenResult) +{ + using T = typename TestFixture::value_type; + using ComplexMtx = typename TestFixture::ComplexMtx; + auto exec = this->mtx5->get_executor(); + // clang-format off + // {1.0, -1.0, -0.5}, + // {-2.0, 2.0, 4.5}, + // {2.1, 3.4, 1.2} + // clang-format on + + auto complex_mtx = ComplexMtx::create(exec, this->mtx5->get_size()); + this->mtx5->make_complex(complex_mtx.get()); + + GKO_ASSERT_MTX_NEAR(complex_mtx, this->mtx5, 0); +} + + +TYPED_TEST(Dense, MakeComplexWithGivenResultFailsForWrongDimensions) +{ + using T = typename TestFixture::value_type; + using ComplexMtx = typename TestFixture::ComplexMtx; + auto exec = this->mtx5->get_executor(); + // clang-format off + // {1.0, -1.0, -0.5}, + // {-2.0, 2.0, 4.5}, + // {2.1, 3.4, 1.2} + // clang-format on + + auto complex_mtx = ComplexMtx::create(exec); + + ASSERT_THROW(this->mtx5->make_complex(complex_mtx.get()), + gko::DimensionMismatch); } @@ -2175,9 +2213,43 @@ TYPED_TEST(Dense, GetReal) // {2.1, 3.4, 1.2} // clang-format on - auto abs_mtx = this->mtx5->get_real(); + auto real_mtx = this->mtx5->get_real(); + + GKO_ASSERT_MTX_NEAR(real_mtx, this->mtx5, 0); +} + + +TYPED_TEST(Dense, GetRealWithGivenResult) +{ + using T = typename TestFixture::value_type; + using RealMtx = typename TestFixture::RealMtx; + auto exec = this->mtx5->get_executor(); + // clang-format off + // {1.0, -1.0, -0.5}, + // {-2.0, 2.0, 4.5}, + // {2.1, 3.4, 1.2} + // clang-format on + + auto real_mtx = RealMtx::create(exec, this->mtx5->get_size()); + this->mtx5->get_real(real_mtx.get()); - GKO_ASSERT_MTX_NEAR(abs_mtx, this->mtx5, r::value); + GKO_ASSERT_MTX_NEAR(real_mtx, this->mtx5, 0); +} + + +TYPED_TEST(Dense, GetRealWithGivenResultFailsForWrongDimensions) +{ + using T = typename TestFixture::value_type; + using RealMtx = typename TestFixture::RealMtx; + auto exec = this->mtx5->get_executor(); + // clang-format off + // {1.0, -1.0, -0.5}, + // {-2.0, 2.0, 4.5}, + // {2.1, 3.4, 1.2} + // clang-format on + + auto real_mtx = RealMtx::create(exec); + ASSERT_THROW(this->mtx5->get_real(real_mtx.get()), gko::DimensionMismatch); } @@ -2190,11 +2262,45 @@ TYPED_TEST(Dense, GetImag) // {2.1, 3.4, 1.2} // clang-format on - auto abs_mtx = this->mtx5->get_imag(); + auto imag_mtx = this->mtx5->get_imag(); - GKO_ASSERT_MTX_NEAR(abs_mtx, - l({{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}), - r::value); + GKO_ASSERT_MTX_NEAR( + imag_mtx, l({{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}), 0); +} + + +TYPED_TEST(Dense, GetImagWithGivenResult) +{ + using T = typename TestFixture::value_type; + using RealMtx = typename TestFixture::RealMtx; + auto exec = this->mtx5->get_executor(); + // clang-format off + // {1.0, -1.0, -0.5}, + // {-2.0, 2.0, 4.5}, + // {2.1, 3.4, 1.2} + // clang-format on + + auto imag_mtx = RealMtx::create(exec, this->mtx5->get_size()); + this->mtx5->get_imag(imag_mtx.get()); + + GKO_ASSERT_MTX_NEAR( + imag_mtx, l({{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}), 0); +} + + +TYPED_TEST(Dense, GetImagWithGivenResultFailsForWrongDimensions) +{ + using T = typename TestFixture::value_type; + using RealMtx = typename TestFixture::RealMtx; + auto exec = this->mtx5->get_executor(); + // clang-format off + // {1.0, -1.0, -0.5}, + // {-2.0, 2.0, 4.5}, + // {2.1, 3.4, 1.2} + // clang-format on + + auto imag_mtx = RealMtx::create(exec); + ASSERT_THROW(this->mtx5->get_imag(imag_mtx.get()), gko::DimensionMismatch); } @@ -2203,6 +2309,7 @@ class DenseComplex : public ::testing::Test { protected: using value_type = T; using Mtx = gko::matrix::Dense; + using RealMtx = gko::matrix::Dense>; }; @@ -2279,9 +2386,28 @@ TYPED_TEST(DenseComplex, MakeComplex) {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, exec); // clang-format on - auto abs_mtx = mtx->make_complex(); + auto complex_mtx = mtx->make_complex(); - GKO_ASSERT_MTX_NEAR(abs_mtx, mtx, 0.0); + GKO_ASSERT_MTX_NEAR(complex_mtx, mtx, 0.0); +} + + +TYPED_TEST(DenseComplex, MakeComplexWithGivenResult) +{ + using Mtx = typename TestFixture::Mtx; + using T = typename TestFixture::value_type; + auto exec = gko::ReferenceExecutor::create(); + // clang-format off + auto mtx = gko::initialize( + {{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, exec); + // clang-format on + + auto complex_mtx = Mtx::create(exec, mtx->get_size()); + mtx->make_complex(complex_mtx.get()); + + GKO_ASSERT_MTX_NEAR(complex_mtx, mtx, 0.0); } @@ -2297,10 +2423,33 @@ TYPED_TEST(DenseComplex, GetReal) {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, exec); // clang-format on - auto abs_mtx = mtx->get_real(); + auto real_mtx = mtx->get_real(); + + GKO_ASSERT_MTX_NEAR( + real_mtx, l({{1.0, 3.0, 0.0}, {-4.0, -1.0, 0.0}, {0.0, 0.0, 2.0}}), + 0.0); +} + + +TYPED_TEST(DenseComplex, GetRealWithGivenResult) +{ + using Mtx = typename TestFixture::Mtx; + using RealMtx = typename TestFixture::RealMtx; + using T = typename TestFixture::value_type; + auto exec = gko::ReferenceExecutor::create(); + // clang-format off + auto mtx = gko::initialize( + {{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, exec); + // clang-format on + + auto real_mtx = RealMtx::create(exec, mtx->get_size()); + mtx->get_real(real_mtx.get()); GKO_ASSERT_MTX_NEAR( - abs_mtx, l({{1.0, 3.0, 0.0}, {-4.0, -1.0, 0.0}, {0.0, 0.0, 2.0}}), 0.0); + real_mtx, l({{1.0, 3.0, 0.0}, {-4.0, -1.0, 0.0}, {0.0, 0.0, 2.0}}), + 0.0); } @@ -2316,10 +2465,33 @@ TYPED_TEST(DenseComplex, GetImag) {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, exec); // clang-format on - auto abs_mtx = mtx->get_imag(); + auto imag_mtx = mtx->get_imag(); GKO_ASSERT_MTX_NEAR( - abs_mtx, l({{0.0, 4.0, 2.0}, {-3.0, 0.0, 0.0}, {0.0, -1.5, 0.0}}), 0.0); + imag_mtx, l({{0.0, 4.0, 2.0}, {-3.0, 0.0, 0.0}, {0.0, -1.5, 0.0}}), + 0.0); +} + + +TYPED_TEST(DenseComplex, GetImagWithGivenResult) +{ + using Mtx = typename TestFixture::Mtx; + using RealMtx = typename TestFixture::RealMtx; + using T = typename TestFixture::value_type; + auto exec = gko::ReferenceExecutor::create(); + // clang-format off + auto mtx = gko::initialize( + {{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, exec); + // clang-format on + + auto imag_mtx = RealMtx::create(exec, mtx->get_size()); + mtx->get_imag(imag_mtx.get()); + + GKO_ASSERT_MTX_NEAR( + imag_mtx, l({{0.0, 4.0, 2.0}, {-3.0, 0.0, 0.0}, {0.0, -1.5, 0.0}}), + 0.0); }