diff --git a/include/kyosu/cayley.hpp b/include/kyosu/cayley.hpp new file mode 100644 index 00000000..c4ea1332 --- /dev/null +++ b/include/kyosu/cayley.hpp @@ -0,0 +1,80 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +//====================================================================================================================== +//! @defgroup functions cayley Functions +//! @brief Functions performing computations over all cayley-dicson types, complex, quaternions and octonions... +//====================================================================================================================== +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/include/kyosu/complex/impl/predicates.hpp b/include/kyosu/complex/impl/predicates.hpp new file mode 100644 index 00000000..5667c272 --- /dev/null +++ b/include/kyosu/complex/impl/predicates.hpp @@ -0,0 +1,19 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once +#include + +namespace kyosu::_ +{ + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& c) noexcept + { + return is_eqz(kyosu::real(c)); + } +} diff --git a/include/kyosu/complex/is_imag.hpp b/include/kyosu/complex/is_imag.hpp new file mode 100644 index 00000000..f6dd8a39 --- /dev/null +++ b/include/kyosu/complex/is_imag.hpp @@ -0,0 +1,74 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_is_imag : eve::elementwise + { + using callable_tag_type = callable_is_imag; + + KYOSU_DEFERS_CALLABLE(is_imag_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::is_eqz(v); } + + template + KYOSU_FORCEINLINE auto operator()(T const& target) const noexcept -> decltype(eve::tag_invoke(*this, target)) + { + return eve::tag_invoke(*this, target); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var is_imag +//! @brief test if the parameter is imag. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto is_imag(T z) noexcept; +//! template constexpr auto is_imag(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns elementwise true the real part of the argument is zero. +//! For Caley-Dickson types of dimension greater than 2 use is_pure. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/is_imag.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_is_imag is_imag = {}; +} diff --git a/include/kyosu/functions.hpp b/include/kyosu/functions.hpp index b5072b0c..0cc002c8 100644 --- a/include/kyosu/functions.hpp +++ b/include/kyosu/functions.hpp @@ -12,6 +12,7 @@ //! @brief Functions performing computations over complex, quaternions and octonions. //====================================================================================================================== #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/include/kyosu/functions/average.hpp b/include/kyosu/functions/average.hpp new file mode 100644 index 00000000..d8f85591 --- /dev/null +++ b/include/kyosu/functions/average.hpp @@ -0,0 +1,78 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +namespace kyosu::tags +{ + struct callable_average : eve::elementwise + { + using callable_tag_type = callable_average; + + KYOSU_DEFERS_CALLABLE(average_); + + static KYOSU_FORCEINLINE auto deferred_call(auto + , eve::ordered_value auto const& v0 + , eve::ordered_value auto const& v1) noexcept + { + return eve::average(v0, v1); + } + + KYOSU_FORCEINLINE auto operator()(auto const& target0, auto const& target1) const noexcept + -> decltype(eve::tag_invoke(*this, target0, target1)) + { + return eve::tag_invoke(*this, target0, target1); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var average +//! @brief Computes the average of the two parameters. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto average(T0 z0, T1, z1) noexcept; +//! template > constexpr auto average(T0 z0, T1, z1) noexcept; +//! template constexpr auto average(T0 z0, T1, z1) noexcept; +//! template > constexpr auto average(T0 z0, T1, z1) noexcept; +///! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z0, z1` : Value to process. +//! +//! **Return value** +//! +//! Returns the average of the two arguments . +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/average.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_average average = {}; +} diff --git a/include/kyosu/functions/is_imag.hpp b/include/kyosu/functions/is_imag.hpp new file mode 100644 index 00000000..33190eaf --- /dev/null +++ b/include/kyosu/functions/is_imag.hpp @@ -0,0 +1,73 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_is_imag : eve::elementwise + { + using callable_tag_type = callable_is_imag; + + KYOSU_DEFERS_CALLABLE(is_imag_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::is_eqz(v); } + + template + KYOSU_FORCEINLINE auto operator()(T const& target) const noexcept -> decltype(eve::tag_invoke(*this, target)) + { + return eve::tag_invoke(*this, target); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var is_imag +//! @brief test if the complex parameter is pure imaginary. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto is_imag(T z) noexcept; +//! template constexpr auto is_imag(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the value of real(z) == 0. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/is_imag.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_is_imag is_imag = {}; +} diff --git a/include/kyosu/types/cayley_dickson.hpp b/include/kyosu/types/cayley_dickson.hpp index 69487e50..6ab99347 100644 --- a/include/kyosu/types/cayley_dickson.hpp +++ b/include/kyosu/types/cayley_dickson.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace kyosu @@ -99,16 +100,6 @@ namespace kyosu return that; } - //================================================================================================================== - // Main function dispatchers - //================================================================================================================== - KYOSU_FORCEINLINE - friend constexpr auto tag_invoke(eve::callable auto const& f, auto, eve::like auto&&... c) noexcept - -> decltype(_::dispatch(f, KYOSU_FWD(c)...)) - { - return _::dispatch(f, KYOSU_FWD(c)...); - } - //================================================================================================================== // Tuple-like behavior //================================================================================================================== @@ -126,6 +117,17 @@ namespace kyosu template constexpr auto get(cayley_dickson const& c) noexcept { return kumi::get(c.contents); } + //================================================================================================================== + // Main function dispatchers + //================================================================================================================== + template + requires(concepts::cayley_dickson || ... ) + KYOSU_FORCEINLINE constexpr auto tag_invoke(eve::callable auto const& f, auto, T&&... c) noexcept + -> decltype(_::dispatch(f, KYOSU_FWD(c)...)) + { + return _::dispatch(f, KYOSU_FWD(c)...); + } + //================================================================================================================== // Tag invoke override for if_else - Outside so it can properly deals with the complicated parameters of if_else //================================================================================================================== @@ -148,7 +150,6 @@ namespace kyosu return _::dispatch(f, c, tgt); } - //================================================================================================================== // Tag invoke override for parts extraction - Outside so they can see get(c) //================================================================================================================== diff --git a/include/kyosu/types/impl/arithmetic.hpp b/include/kyosu/types/impl/arithmetic.hpp index 58914280..72d6cf7e 100644 --- a/include/kyosu/types/impl/arithmetic.hpp +++ b/include/kyosu/types/impl/arithmetic.hpp @@ -9,7 +9,7 @@ #include #include - +#include namespace kyosu::_ { template @@ -119,17 +119,21 @@ namespace kyosu::_ } } - template + template KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C0 const & c0, C1 const & c1) noexcept { return kyosu::abs(c0-c1); } - template + template KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C0 const & c0, C1 const & c1) noexcept { +// using r_t = kyosu::as_cayley_dickson_t; +// using er_t = eve::element_type_t; +// auto cc0 = kyosu::convert(c0, eve::as()); +// auto cc1 = kyosu::convert(c1, eve::as()); return kyosu::dist(c0, c1)/eve::max(kyosu::abs(c0), kyosu::abs(c1), eve::one(eve::as(abs(c0)))); } @@ -201,4 +205,19 @@ namespace kyosu::_ { return kyosu::if_else(kyosu::is_nez(c), c/abs(c), C(0)); } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C0 const & c0, C1 const & c1) noexcept + { + using r_t = kyosu::as_cayley_dickson_t; + using er_t = eve::element_type_t; + return r_t{kumi::map([](auto const& e, auto const& f) { return eve::average(e, f); } + , kyosu::convert(c0, eve::as()) + , kyosu::convert(c1, eve::as()) + ) + }; + } + + } diff --git a/include/kyosu/types/impl/complex/predicates.hpp b/include/kyosu/types/impl/complex/predicates.hpp new file mode 100644 index 00000000..9398fbcc --- /dev/null +++ b/include/kyosu/types/impl/complex/predicates.hpp @@ -0,0 +1,21 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::_ +{ + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& c) noexcept + { + return eve::is_eqz(kyosu::real(c)); + } + +} diff --git a/include/kyosu/types/impl/trigo.hpp b/include/kyosu/types/impl/trigo.hpp index 60ac6b15..a2c3d651 100644 --- a/include/kyosu/types/impl/trigo.hpp +++ b/include/kyosu/types/impl/trigo.hpp @@ -35,7 +35,7 @@ namespace kyosu::_ else { auto e = kyosu::exp(z); - return eve::average(e, rec(e)); + return kyosu::average(e, rec(e)); } } diff --git a/test/doc/average.cpp b/test/doc/average.cpp new file mode 100644 index 00000000..0e579556 --- /dev/null +++ b/test/doc/average.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +int main() +{ + using kyosu::average; + using kyosu::complex; + using kyosu::quaternion; + using e_t = float; + using c_t = complex; + using q_t = quaternion; + using we_t = eve::wide>; + using wc_t = eve::wide, eve::fixed<2>>; + using wq_t = eve::wide, eve::fixed<2>>; + + std::cout << "Real: "<< "\n"; + e_t e0(1); + e_t e1(2); + std::cout << e0 << ", " << e1 << " -> " << average(e0, e1) << "\n"; + std::cout << e0 << ", " << e0 << " -> " << average(e0, e0) << "\n"; + we_t we0(e0); + we_t we1(e1); + std::cout << we0 << ", " << we1 << " -> " << average(we0, we1) << "\n"; + + std::cout << "Complex: "<< "\n"; + c_t c0(1, 5); + c_t c1(5, 9); + std::cout << c0 << ", " << c1 << " -> " << average(c0, c1) << "\n"; + std::cout << c0 << ", " << c0 << " -> " << average(c0, c0) << "\n"; + wc_t wc0(c0, c1); + wc_t wc1(c1, c1); + std::cout << wc0 << ", " << wc1 << " -> " << average(wc0, wc1) << "\n"; + + std::cout << "Quaternion: "<< "\n"; + q_t q0(1, 5, 2, 3); + q_t q1(5, 9, 6, 7); + std::cout << q0 << ", " << q1 << " -> " << average(q0, q1) << "\n"; + std::cout << q0 << ", " << q0 << " -> " << average(q0, q0) << "\n"; + wq_t wq0(q0, q1); + wq_t wq1(q1, q1); + std::cout << wq0 << ", " << wq1 << " -> " << average(wq0, wq1) << "\n"; + + std::cout << "Mixed: "<< "\n"; + std::cout << kyosu::average(c0, q1) << std::endl; + std::cout << kyosu::average(e0, q1) << std::endl; + std::cout << kyosu::average(c0, wq1) << std::endl; + std::cout << kyosu::average(we0, q1) << std::endl; + + return 0; +} diff --git a/test/doc/dist.cpp b/test/doc/dist.cpp index 7db417d4..c10b2fde 100644 --- a/test/doc/dist.cpp +++ b/test/doc/dist.cpp @@ -37,6 +37,8 @@ int main() wq_t wq0(q0); wq_t wq1(q1); std::cout << wq0 << ", " << wq1 << " -> " << dist(wq0, wq1) << "\n"; + std::cout << wq0 << ", " << q1 << " -> " << dist(wq0, q1) << "\n"; + std::cout << wq0 << ", " << e1 << " -> " << dist(wq0, e1) << "\n"; return 0; } diff --git a/test/doc/reldist.cpp b/test/doc/reldist.cpp index 6ebc78c5..20e7a96c 100644 --- a/test/doc/reldist.cpp +++ b/test/doc/reldist.cpp @@ -37,6 +37,8 @@ int main() wq_t wq0(q0); wq_t wq1(q1); std::cout << wq0 << ", " << wq1 << " -> " << reldist(wq0, wq1) << "\n"; + std::cout << wq0 << ", " << q1 << " -> " << reldist(wq0, q1) << "\n"; + std::cout << wq0 << ", " << e1 << " -> " << reldist(wq0, e1) << "\n"; return 0; } diff --git a/test/unit/complex/is_imag.cpp b/test/unit/complex/is_imag.cpp new file mode 100644 index 00000000..7b8a49d0 --- /dev/null +++ b/test/unit/complex/is_imag.cpp @@ -0,0 +1,44 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include +#include + +template < typename T > +auto cv(std::complex < T > const &sc) +{ + return kyosu::to_complex(sc.real(), sc.imag()); +} + +TTS_CASE_WITH( "Check behavior of cos on scalar" + , tts::bunch + , tts::generate( tts::randoms(-10, 10), tts::randoms(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = typename T::value_type; + using kc_t = kyosu::as_complex_t; + for(size_t i = 0; i < a0.size(); ++i) + { + auto e = a0[i]; + auto f = a1[i]; + auto z = kc_t(e, f); + TTS_EQUAL(kyosu::is_imag(z), eve::is_eqz(kyosu::real(z))); + } +}; + +TTS_CASE_WITH( "Check behavior of cos on wide" + , kyosu::simd_real_types + , tts::generate( tts::between(-10, 10) + , tts::between(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + auto z = kyosu::to_complex(a0, a1); + TTS_EQUAL(kyosu::is_imag(z), eve::is_eqz(kyosu::real(z))); +};