Skip to content

Commit

Permalink
Merge pull request #1828 from JohanMabille/complex_batch
Browse files Browse the repository at this point in the history
Fixed assignment of scalar to complex
  • Loading branch information
JohanMabille committed Nov 30, 2019
2 parents 60ae196 + d806243 commit 940c3a0
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 3 deletions.
36 changes: 33 additions & 3 deletions include/xtensor/xassign.hpp
Expand Up @@ -14,6 +14,7 @@
#include <type_traits>
#include <utility>

#include <xtl/xcomplex.hpp>
#include <xtl/xsequence.hpp>

#include "xexpression.hpp"
Expand Down Expand Up @@ -291,6 +292,33 @@ namespace xt
{
static constexpr bool value = xtl::conjunction<use_strided_loop<std::decay_t<CT>>...>::value;
};

/**
* Considering the assigment LHS = RHS, if the requested value type used for
* loading simd form RHS is not complex while LHS value_type is complex,
* the assignment fails. The reason is that SIMD batches of complex values cannot
* be implicitly instanciated from batches of scalar values.
* Making the constructor implicit does not fix the issue since in the end,
* the assignment is done with vec.store(buffer) where vec is a batch of scalars
* and buffer an array of complex. SIMD batches of scalars do not provide overloads
* of store that accept buffer of commplex values and that SHOULD NOT CHANGE.
* Load and store overloads must accept SCALAR BUFFERS ONLY.
* Therefore, the solution is to explicitly force the instantiation of complex
* batches in the assignment mechanism. A common situation tthat triggers this
* issue is:
* xt::xarray<double> rhs = { 1, 2, 3 };
* xt::xarray<std::complex<double>> lhs = rhs;
*/
template <class T1, class T2>
struct conditional_promote_to_complex
{
static constexpr bool cond = xtl::is_gen_complex<T1>::value && !xtl::is_gen_complex<T2>::value;
// Alternative: use std::complex<T2> or xcomplex<T2, T2, bool> depending on T1
using type = std::conditional_t<cond, T1, T2>;
};

template <class T1, class T2>
using conditional_promote_to_complex_t = typename conditional_promote_to_complex<T1, T2>::type;
}

template <class E1, class E2>
Expand Down Expand Up @@ -330,9 +358,11 @@ namespace xt
static constexpr bool simd_linear_assign(const E1& e1, const E2& e2) { return simd_assign()
&& detail::linear_dynamic_layout(e1, e2); }

using requested_value_type = std::conditional_t<is_bool<e2_value_type>::value,
typename E2::bool_load_type,
e2_value_type>;
using e2_requested_value_type = std::conditional_t<is_bool<e2_value_type>::value,
typename E2::bool_load_type,
e2_value_type>;
using requested_value_type = detail::conditional_promote_to_complex_t<e1_value_type,
e2_requested_value_type>;

};

Expand Down
9 changes: 9 additions & 0 deletions test/test_xcomplex.cpp
Expand Up @@ -297,4 +297,13 @@ namespace xt
EXPECT_EQ(a(0, 0), cmplx(-123.321, -123.321));
EXPECT_EQ(a(4, 4), cmplx(-123.321, -123.321));
}

TEST(xcomplex, build_from_double)
{
xt::xarray<double> r = { 1., 2., 3. };
xt::xarray<std::complex<double>> rc(r);
EXPECT_EQ(rc(0).real(), r(0));
EXPECT_EQ(rc(1).real(), r(1));
EXPECT_EQ(rc(2).real(), r(2));
}
}

0 comments on commit 940c3a0

Please sign in to comment.