/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTENSOR_COMPLEX_HPP #define XTENSOR_COMPLEX_HPP #include #include #include #include "xtensor/xbuilder.hpp" #include "xtensor/xexpression.hpp" #include "xtensor/xoffset_view.hpp" namespace xt { /** * @defgroup xt_xcomplex * * Defined in ``xtensor/xcomplex.hpp`` */ /****************************** * real and imag declarations * ******************************/ template decltype(auto) real(E&& e) noexcept; template decltype(auto) imag(E&& e) noexcept; /******************************** * real and imag implementation * ********************************/ namespace detail { template struct complex_helper { template inline static auto real(E&& e) noexcept { using real_type = typename std::decay_t::value_type::value_type; return xoffset_view, real_type, 0>(std::forward(e)); } template inline static auto imag(E&& e) noexcept { using real_type = typename std::decay_t::value_type::value_type; return xoffset_view, real_type, sizeof(real_type)>(std::forward(e)); } }; template <> struct complex_helper { template inline static decltype(auto) real(E&& e) noexcept { return std::forward(e); } template inline static auto imag(E&& e) noexcept { return zeros::value_type>(e.shape()); } }; template struct complex_expression_helper { template inline static decltype(auto) real(E&& e) noexcept { return detail::complex_helper::value_type>::value>::real( std::forward(e) ); } template inline static decltype(auto) imag(E&& e) noexcept { return detail::complex_helper::value_type>::value>::imag( std::forward(e) ); } }; template <> struct complex_expression_helper { template inline static decltype(auto) real(E&& e) noexcept { return xtl::forward_real(std::forward(e)); } template inline static decltype(auto) imag(E&& e) noexcept { return xtl::forward_imag(std::forward(e)); } }; } /** * Return an xt::xexpression representing the real part of the given expression. * * The returned expression either hold a const reference to @p e or a copy * depending on whether @p e is an lvalue or an rvalue. * * @ingroup xt_xcomplex * @tparam e The xt::xexpression */ template inline decltype(auto) real(E&& e) noexcept { return detail::complex_expression_helper>::value>::real(std::forward(e )); } /** * Return an xt::xexpression representing the imaginary part of the given expression. * * The returned expression either hold a const reference to @p e or a copy * depending on whether @p e is an lvalue or an rvalue. * * @ingroup xt_xcomplex * @tparam e The xt::xexpression */ template inline decltype(auto) imag(E&& e) noexcept { return detail::complex_expression_helper>::value>::imag(std::forward(e )); } #define UNARY_COMPLEX_FUNCTOR(NS, NAME) \ struct NAME##_fun \ { \ template \ constexpr auto operator()(const T& t) const \ { \ using NS::NAME; \ return NAME(t); \ } \ \ template \ constexpr auto simd_apply(const B& t) const \ { \ using NS::NAME; \ return NAME(t); \ } \ } namespace math { namespace detail { template constexpr std::complex conj_impl(const std::complex& c) { return std::complex(c.real(), -c.imag()); } template constexpr std::complex conj_impl(const T& real) { return std::complex(real, 0); } #ifdef XTENSOR_USE_XSIMD template xsimd::complex_batch_type_t> conj_impl(const xsimd::batch& z) { return xsimd::conj(z); } #endif } UNARY_COMPLEX_FUNCTOR(std, norm); UNARY_COMPLEX_FUNCTOR(std, arg); UNARY_COMPLEX_FUNCTOR(detail, conj_impl); } #undef UNARY_COMPLEX_FUNCTOR /** * Return an xt::xfunction evaluating to the complex conjugate of the given expression. * * @ingroup xt_xcomplex * @param e the xt::xexpression */ template inline auto conj(E&& e) noexcept { using functor = math::conj_impl_fun; using type = xfunction>; return type(functor(), std::forward(e)); } /** * Calculates the phase angle (in radians) elementwise for the complex numbers in @p e. * * @ingroup xt_xcomplex * @param e the xt::xexpression */ template inline auto arg(E&& e) noexcept { using functor = math::arg_fun; using type = xfunction>; return type(functor(), std::forward(e)); } /** * Calculates the phase angle elementwise for the complex numbers in @p e. * * Note that this function might be slightly less performant than xt::arg. * * @ingroup xt_xcomplex * @param e the xt::xexpression * @param deg calculate angle in degrees instead of radians */ template inline auto angle(E&& e, bool deg = false) noexcept { using value_type = xtl::complex_value_type_t::value_type>; value_type multiplier = 1.0; if (deg) { multiplier = value_type(180) / numeric_constants::PI; } return arg(std::forward(e)) * std::move(multiplier); } /** * Calculates the squared magnitude elementwise for the complex numbers in @p e. * * Equivalent to ``xt::pow(xt::real(e), 2) + xt::pow(xt::imag(e), 2)``. * @ingroup xt_xcomplex * @param e the xt::xexpression */ template inline auto norm(E&& e) noexcept { using functor = math::norm_fun; using type = xfunction>; return type(functor(), std::forward(e)); } } #endif