Skip to content

Commit

Permalink
Implements convert and use it to fix cross-SIMD operators behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
jfalcou committed Aug 29, 2023
1 parent 02b32cd commit a2bb7d9
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 16 deletions.
1 change: 1 addition & 0 deletions include/kyosu/functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <kyosu/functions/conj.hpp>
#include <kyosu/functions/cosh.hpp>
#include <kyosu/functions/coth.hpp>
#include <kyosu/functions/convert.hpp>
#include <kyosu/functions/dec.hpp>
#include <kyosu/functions/dist.hpp>
#include <kyosu/functions/exp.hpp>
Expand Down
76 changes: 76 additions & 0 deletions include/kyosu/functions/convert.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//======================================================================================================================
/*
Kyosu - Complex Without Complexes
Copyright : KYOSU Contributors & Maintainers
SPDX-License-Identifier: BSL-1.0
*/
//======================================================================================================================
#pragma once

#include <kyosu/details/invoke.hpp>

namespace kyosu::tags
{
struct callable_convert : eve::elementwise
{
using callable_tag_type = callable_convert;

KYOSU_DEFERS_CALLABLE(convert_);

template<eve::plain_scalar_value T>
static KYOSU_FORCEINLINE auto deferred_call(auto, eve::ordered_value auto const& v, eve::as<T> const& tgt) noexcept
{
return eve::convert(v,tgt);
}

template<typename T>
KYOSU_FORCEINLINE
auto operator()(auto const& v, eve::as<T> const& tgt) const noexcept -> decltype(eve::tag_invoke(*this,v,tgt))
{
return eve::tag_invoke(*this, v, tgt);
}

template<typename... T>
eve::unsupported_call<callable_convert(T&&...)> operator()(T&&... x) const
requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete;
};
}

namespace kyosu
{
//======================================================================================================================
//! @addtogroup functions
//! @{
//! @var convert
//! @brief Select a value between two arguments based on a logical mask
//!
//! **Defined in Header**
//!
//! @code
//! #include <kyosu/functions.hpp>
//! @endcode
//!
//! @groupheader{Callable Signatures}
//!
//! @code
//! namespace kyosu
//! {
//! template<eve::value T, eve::value U, eve::value V>
//! constexpr auto convert(T x, U, y, V z ) noexcept;
//! }
//! @endcode
//!
//! **Parameters**
//!
//! * `z` : Value to process.
//!
//! **Return value**
//!
//!
//! @groupheader{Example}
//!
//! @godbolt{doc/convert.cpp}
//! @}
//======================================================================================================================
inline constexpr tags::callable_convert convert = {};
}
12 changes: 11 additions & 1 deletion include/kyosu/types/cayley_dickson.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ namespace kyosu
return _::dispatch(fn, m,t,f);
}

template<concepts::cayley_dickson T, eve::value C>
requires( eve::scalar_value<T> )
KYOSU_FORCEINLINE
constexpr auto tag_invoke( eve::tag_of<kyosu::convert> const& f, auto, C const& c, eve::as<T> const& tgt) noexcept
-> decltype(_::dispatch(f, c, tgt))
{
return _::dispatch(f, c, tgt);
}


//==================================================================================================================
// Tag invoke override for parts extraction - Outside so they can see get<I>(c)
//==================================================================================================================
Expand Down Expand Up @@ -204,7 +214,7 @@ struct std::tuple_element<I, kyosu::cayley_dickson<T,N>>
template<typename Wrapper, typename T, unsigned int N>
struct eve::supports_like<Wrapper,kyosu::cayley_dickson<T,N>>
: std::bool_constant< kyosu::concepts::cayley_dickson<Wrapper>
|| std::same_as<T, element_type_t<Wrapper>>
|| std::same_as<T, eve::element_type_t<Wrapper>>
|| plain_scalar_value<Wrapper>
>
{
Expand Down
19 changes: 17 additions & 2 deletions include/kyosu/types/impl/arithmetic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ namespace kyosu::_
{
using r_t = as_cayley_dickson_t<C0,C1,T>;
return r_t{kumi::map([&t](auto const& e, auto const & f) { return eve::lerp(e, f, t); }, c0, c1)};
}
}

template<typename C>
KYOSU_FORCEINLINE constexpr
Expand Down Expand Up @@ -174,5 +174,20 @@ namespace kyosu::_
auto dispatch(eve::tag_of<kyosu::rec> const&, C c) noexcept
{
return conj(c)/sqr_abs(c);
}
}
template<typename C0, concepts::cayley_dickson C1>
requires(dimension_v<C0> <= dimension_v<C1>)
KYOSU_FORCEINLINE constexpr
auto dispatch(eve::tag_of<convert> const&, C0 const & c, eve::as<C1> const & tgt) noexcept
{
using type = eve::as_wide_as_t<C1, C0>;

if constexpr(std::same_as<eve::element_type_t<C0>,C1>) return c;
else if constexpr(dimension_v<C0> == 1ULL) return type{c};
else
{
using u_t = eve::underlying_type_t<C1>;
return kumi::apply([](auto const&... e) { return type{kyosu::convert(e, eve::as<u_t>{})...}; }, c);
}
}
}
20 changes: 13 additions & 7 deletions include/kyosu/types/impl/operators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ namespace kyosu
/// Returns the sum of a Caley-dickson value and a real value in any order
template<eve::value T1, eve::value T2>
requires(concepts::cayley_dickson<T1> || concepts::cayley_dickson<T2>)
as_cayley_dickson_t<T1,T2> operator+(T1 const& a, T2 const& b) noexcept
auto operator+(T1 const& a, T2 const& b) noexcept -> as_cayley_dickson_t<T1,T2>
{
as_cayley_dickson_t<T1,T2> that{a};
using type = as_cayley_dickson_t<T1,T2>;
type that{kyosu::convert(a,eve::as<eve::element_type_t<type>>())};
return that += b;
}

Expand All @@ -53,7 +54,8 @@ namespace kyosu
requires(concepts::cayley_dickson<T1> || concepts::cayley_dickson<T2>)
as_cayley_dickson_t<T1,T2> operator-(T1 const& a, T2 const& b) noexcept
{
as_cayley_dickson_t<T1,T2> that{a};
using type = as_cayley_dickson_t<T1,T2>;
type that{kyosu::convert(a,eve::as<eve::element_type_t<type>>())};
return that -= b;
}

Expand All @@ -62,7 +64,8 @@ namespace kyosu
requires(concepts::cayley_dickson<T1> && concepts::cayley_dickson<T2>)
as_cayley_dickson_t<T1,T2> operator*(T1 const& a, T2 const& b) noexcept
{
as_cayley_dickson_t<T1,T2> that{a};
using type = as_cayley_dickson_t<T1,T2>;
type that{kyosu::convert(a,eve::as<eve::element_type_t<type>>())};
return that *= b;
}

Expand All @@ -73,12 +76,14 @@ namespace kyosu
// This is ok as the non cayley-dickson type is a scalar
if constexpr(concepts::cayley_dickson<T1>)
{
as_cayley_dickson_t<T1,T2> that{a};
using type = as_cayley_dickson_t<T1,T2>;
type that{kyosu::convert(a,eve::as<eve::element_type_t<type>>())};
return that *= b;
}
else
{
as_cayley_dickson_t<T1,T2> that{b};
using type = as_cayley_dickson_t<T1,T2>;
type that{kyosu::convert(b,eve::as<eve::element_type_t<type>>())};
return that *= a;
}
}
Expand All @@ -88,7 +93,8 @@ namespace kyosu
requires(concepts::cayley_dickson<T1> || concepts::cayley_dickson<T2>)
as_cayley_dickson_t<T1,T2> operator/(T1 const& a, T2 const& b) noexcept
{
as_cayley_dickson_t<T1,T2> that{a};
using type = as_cayley_dickson_t<T1,T2>;
type that{kyosu::convert(a,eve::as<eve::element_type_t<type>>())};
return that /= b;
}

Expand Down
7 changes: 1 addition & 6 deletions include/kyosu/types/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,7 @@ namespace kyosu

template<unsigned int Dim, typename... Ts>
requires( Dim > 1 && !requires(Ts... ts) { eve::add( std::declval<_::sema_t<Ts>>()...); } )
struct as_cayley_dickson_n<Dim, Ts...>
{
static_assert ( requires(Ts... ts) { eve::add( std::declval<_::sema_t<Ts>>()...); }
, "[KYOSU] - STATIC ASSERT: Incompatible types in type resolution"
);
};
struct as_cayley_dickson_n<Dim, Ts...> {};

template<unsigned int Dim, typename T>
requires(Dim > 1)
Expand Down

0 comments on commit a2bb7d9

Please sign in to comment.