Add support for hypot function

Issue #148 resolved
Nils Deppe created an issue

Hi again Klaus!

I hope things are well with you. I just added the hypot function to our code base for use with Blaze and thought I'd share the implementation so that you can tweak it and add it to Blaze. Thanks!

namespace blaze {
template <typename T0, typename T1>
BLAZE_ALWAYS_INLINE const SIMDfloat hypot(const SIMDf32<T0>& a,
                                          const SIMDf32<T1>& b) noexcept
#if BLAZE_SVML_MODE && (BLAZE_AVX512F_MODE || BLAZE_MIC_MODE)
{
  return _mm512_hypot_ps((~a).eval().value, (~b).eval().value);
}
#elif BLAZE_SVML_MODE && BLAZE_AVX_MODE
{
  return _mm256_hypot_ps((~a).eval().value, (~b).eval().value);
}
#elif BLAZE_SVML_MODE && BLAZE_SSE_MODE
{
  return _mm_hypot_ps((~a).eval().value, (~b).eval().value);
}
#else
    = delete;
#endif

template <typename T0, typename T1>
BLAZE_ALWAYS_INLINE const SIMDdouble hypot(const SIMDf64<T0>& a,
                                           const SIMDf64<T1>& b) noexcept
#if BLAZE_SVML_MODE && (BLAZE_AVX512F_MODE || BLAZE_MIC_MODE)
{
  return _mm512_hypot_pd((~a).eval().value, (~b).eval().value);
}
#elif BLAZE_SVML_MODE && BLAZE_AVX_MODE
{
  return _mm256_hypot_pd((~a).eval().value, (~b).eval().value);
}
#elif BLAZE_SVML_MODE && BLAZE_SSE_MODE
{
  return _mm_hypot_pd((~a).eval().value, (~b).eval().value);
}
#else
    = delete;
#endif

template <typename T0, typename T1>
using HasSIMDHypot = std::integral_constant<
    bool, std::is_same<std::decay_t<T0>, std::decay_t<T1>>::value and
              std::is_arithmetic<std::decay_t<T0>>::value and bool(  // NOLINT
                  BLAZE_SVML_MODE) and                               // NOLINT
              (bool(BLAZE_SSE_MODE) || bool(BLAZE_AVX_MODE) ||       // NOLINT
               bool(BLAZE_MIC_MODE) || bool(BLAZE_AVX512F_MODE))>;   // NOLINT

struct Hypot {
  template <typename T1, typename T2>
  BLAZE_ALWAYS_INLINE decltype(auto) operator()(const T1& a, const T2& b) const
      noexcept {
    using std::hypot;
    return hypot(a, b);
  }

  template <typename T1, typename T2>
  static constexpr bool simdEnabled() noexcept {
    return HasSIMDHypot<T1, T2>::value;
  }

  template <typename T1, typename T2>
  BLAZE_ALWAYS_INLINE decltype(auto) load(const T1& a, const T2& b) const
      noexcept {
    using std::hypot;
    BLAZE_CONSTRAINT_MUST_BE_SIMD_PACK(T1);
    BLAZE_CONSTRAINT_MUST_BE_SIMD_PACK(T2);
    return hypot(a, b);
  }
};
}  // namespace blaze

template <typename VT0, typename VT1, bool TF>
BLAZE_ALWAYS_INLINE decltype(auto) hypot(
    const blaze::DenseVector<VT0, TF>& y,
    const blaze::DenseVector<VT1, TF>& x) noexcept {
  return map(~y, ~x, blaze::Hypot{});
}

Best,

Nils

Comments (5)

  1. Klaus Iglberger

    Hi Nils!

    Thanks a lot for this perfect support :-) We will integrate this as soon as possible and definitely before the release of Blaze 3.3.

    Best regards,

    Klaus!

  2. Klaus Iglberger

    Summary

    The feature has been implemented, tested, optimized, and documented as required. It is immediately available via cloning the Blaze repository and will be officially released in Blaze 3.3.

    The hypot() Function

    The hypot() function can be used to compute the componentwise hypotenous for a pair of dense vectors:

    blaze::StaticVector<double,3UL> a, b, c;
    
    c = hypot( a, b );  // Computes the componentwise hypotenuous
    
    blaze::StaticMatrix<double,3UL,3UL> A, B, C;
    
    C = hypot( A, B );  // Computes the componentwise hypotenuous
    

    The operation is vectorized for SSE, AVX, and AVX-512 via the SVML. Additionally, the operation runs in parallel for large enough vectors and matrices (see for instance the OpenMP configuration).

  3. Log in to comment