Skip to content

Commit

Permalink
Re-establishing horner with ranges as required by some external projects
Browse files Browse the repository at this point in the history
  • Loading branch information
jtlap authored Jan 3, 2024
1 parent f7c1911 commit 32ff9be
Show file tree
Hide file tree
Showing 11 changed files with 296 additions and 23 deletions.
53 changes: 53 additions & 0 deletions include/eve/module/core/decorator/compensated.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//==================================================================================================
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once

#include <eve/detail/overload.hpp>

namespace eve
{

//================================================================================================
//================================================================================================
// Function decorators mark-up used in function overloads
struct compensated_
{
template<typename D> static constexpr auto combine(D const&) noexcept = delete;
};

using compensated_type = decorated<compensated_()>;
//================================================================================================
//! @addtogroup core_decorators
//! @{
//! @var compensated
//!
//! @brief Higher-order @callable imbuing more accuracy onto other @callable{s}.
//!
//! #### Synopsis
//!
//! if compensated(eve::fname) is to be called then
//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
//! #include <eve/module/core.hpp>
//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! must be included.
//!
//! #### Members Functions
//!
//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
//! auto operator()(eve::callable auto const& f ) const noexcept;
//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//! @param f
//! An instance of eve::callable
//!
//! @return
//! A @callable performing the same kind of operation but ensuring a higher accuracy.
//!
//! @}
//================================================================================================
inline constexpr compensated_type const compensated = {};
}
5 changes: 5 additions & 0 deletions include/eve/module/core/decorator/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//======================================================================================================================
#pragma once

#include <eve/module/core/decorator/compensated.hpp>
#include <eve/module/core/decorator/cyl.hpp>
#include <eve/module/core/decorator/fuzzy.hpp>
#include <eve/module/core/decorator/kind.hpp>
Expand All @@ -30,6 +31,7 @@
namespace eve
{
struct almost_mode {};
struct compensated_mode {};
struct definitely_mode {};
struct kind_1_mode {};
struct kind_2_mode {};
Expand Down Expand Up @@ -60,6 +62,7 @@ namespace eve
[[maybe_unused]] inline constexpr auto rounding = (rounding_key = eve::index<N>);

[[maybe_unused]] inline constexpr auto almost2 = ::rbr::flag( almost_mode{} );
[[maybe_unused]] inline constexpr auto compensated2 = ::rbr::flag( compensated_mode{});
[[maybe_unused]] inline constexpr auto definitely2 = ::rbr::flag( definitely_mode{});
[[maybe_unused]] inline constexpr auto downward2 = rounding<(0x01 | 0x08)>;
[[maybe_unused]] inline constexpr auto kind_12 = ::rbr::flag( kind_1_mode{} );
Expand All @@ -82,6 +85,7 @@ namespace eve
[[maybe_unused]] inline constexpr auto upward2 = rounding<(0x02 | 0x08)>;

struct almost_option : detail::exact_option<almost2> {};
struct compensated_option : detail::exact_option<compensated2> {};
struct definitely_option : detail::exact_option<definitely2> {};
struct kind_1_option : detail::exact_option<kind_12> {};
struct kind_2_option : detail::exact_option<kind_22> {};
Expand All @@ -104,6 +108,7 @@ namespace eve
// [TEMPORARY] Will be removed when all decorator have been converted
// ----------------------------------------------------------------------------------
inline constexpr auto as_option(almost_type const&) { return almost2; }
inline constexpr auto as_option(compensated_type const&) { return compensated2; }
inline constexpr auto as_option(definitely_type const&) { return definitely2; }
inline constexpr auto as_option(downward_type const&) { return downward2; }
inline constexpr auto as_option(kind_1_type const&) { return kind_12; }
Expand Down
42 changes: 42 additions & 0 deletions include/eve/module/core/detail/poleval.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//==================================================================================================
/*
EVE - Expressive Vector Engine
Copyright : EVE Project Contributors
SPDX-License-Identifier: BSL-1.0
*/
//==================================================================================================
#pragma once

#include <eve/detail/abi.hpp>
#include <eve/detail/overload.hpp>
#include <eve/module/core/constant/one.hpp>
#include <eve/module/core/constant/zero.hpp>
#include <eve/module/core/regular/fma.hpp>

namespace eve::detail
{
template<typename T, typename A>
auto
poleval(T x, A const& coefs)
{
auto p = coefs.begin();
if( coefs.end() == p ) return zero(as(x));
auto r = T(*p++);

while( p != coefs.end() ) { r = fma(r, x, *p++); }
return r;
}

template<typename T, typename A>
auto
poleval1(T x, A const& coefs)
{
auto p = coefs.begin();
if( coefs.end() == p ) return one(as(x));
auto r = x + T(*p++);

while( p != coefs.end() ) { r = fma(r, x, *p++); }
return r;
}

}
57 changes: 56 additions & 1 deletion include/eve/module/polynomial/detail/horner_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace eve::detail
// }
// }

// This implementation is use for left-polynomial evalution (even for quaternion or octonion)
// This implementation is used for left-polynomial evaluation (even for quaternion or octonion)
//

template<decorator D, value T0, value... Cs>
Expand All @@ -69,4 +69,59 @@ namespace eve::detail
return that;
}
}


//================================================================================================
//== Horner with ranges
//================================================================================================
template<decorator D, value T0, range R>
EVE_FORCEINLINE constexpr auto
horner_impl(D const& d, T0 xx, R const& r) noexcept
-> common_value_t<T0, typename R::value_type>
{
using r_t = common_value_t<T0, typename R::value_type>;
auto x = r_t(xx);
auto cur = std::begin(r);
auto last = std::end(r);
if( last == cur ) return r_t(0);
else if( std::distance(cur, last) == 1 ) return r_t(*cur);
else
{
using std::advance;
auto dfma = d(fma);
auto that = r_t(*cur);
auto step = [&](auto that, auto arg) { return dfma(x, that, arg); };
for( advance(cur, 1); cur != last; advance(cur, 1) ) that = step(that, *cur);
return that;
}
}

template<value T0, range R>
EVE_FORCEINLINE constexpr auto
horner_impl(compensated_type const&, T0 xx, R const& r) noexcept
-> common_value_t<T0, typename R::value_type>
{
using r_t = common_value_t<T0, typename R::value_type>;
auto x = r_t(xx);
auto cur = std::begin(r);
auto last = std::end(r);
if( last == cur ) return r_t(0);
else if( std::distance(cur, last) == 1 ) return r_t(*cur);
else
{
using std::advance;
auto that {r_t(*cur)};
auto err {zero(as<r_t>())};
auto step = [&x, &that, &err](auto arg)
{
auto [pi, epi] = two_prod(x, that);
auto [th, si] = two_add(pi, arg);
that = th;
err = fma(err, x, epi + si);
};
for( advance(cur, 1); cur != last; advance(cur, 1) ) step(r_t(*cur));
return that + err;
}
}

}
58 changes: 41 additions & 17 deletions include/eve/module/polynomial/detail/reverse_horner_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,50 @@
namespace eve::detail
{

template<decorator D, value T0, value C0, value... Cs>
EVE_FORCEINLINE constexpr auto
reverse_horner_impl(D const& d, T0 xx, C0 c0, Cs... cs) noexcept
-> decltype(horner(xx, c0, cs...))
{
if constexpr((scalar_value<C0> && ... && scalar_value<Cs>))
template<decorator D, value T0, value C0, value... Cs>
EVE_FORCEINLINE constexpr auto
reverse_horner_impl(D const& d, T0 xx, C0 c0, Cs... cs) noexcept
-> decltype(horner(xx, c0, cs...))
{
using e_t = element_type_t<T0>;
using t_t = kumi::result::generate_t<sizeof...(cs)+1, e_t>;
t_t c{e_t(c0), e_t(cs)...};
return d(reverse_horner)(xx, c);
if constexpr((scalar_value<C0> && ... && scalar_value<Cs>))
{
using e_t = element_type_t<T0>;
using t_t = kumi::result::generate_t<sizeof...(cs)+1, e_t>;
t_t c{e_t(c0), e_t(cs)...};
return d(reverse_horner)(xx, c);
}
else
{
using r_t = common_value_t<T0, C0, Cs...>;
auto x = r_t(xx);
using t_t = kumi::result::generate_t<sizeof...(cs)+1, r_t>;
t_t c {r_t{c0}, r_t{cs}...};
return d(reverse_horner)(x, c);
}
}
else

//================================================================================================
//== Reverse_Horner with ranges
//================================================================================================
template<decorator D, value T0, range R>
EVE_FORCEINLINE constexpr auto
reverse_horner_impl(D const& d, T0 xx, R const& r) noexcept
-> common_value_t<T0, typename R::value_type>
{
using r_t = common_value_t<T0, C0, Cs...>;
auto x = r_t(xx);
using t_t = kumi::result::generate_t<sizeof...(cs)+1, r_t>;
t_t c {r_t{c0}, r_t{cs}...};
return d(reverse_horner)(x, c);
using r_t = common_value_t<T0, typename R::value_type>;
auto x = r_t(xx);
auto cur = std::rbegin(r);
auto first = std::rend(r);
if( first == cur ) return r_t(0);
else if( std::distance(cur, first) == 1 ) return r_t(*cur);
else
{
auto dfma = d(fma);
auto that = r_t(0);
auto step = [&](auto that, auto arg) { return dfma(x, that, arg); };
for(; cur != first; ++cur ) that = step(that, *cur);
return that;
}
}
}

}
4 changes: 2 additions & 2 deletions include/eve/module/polynomial/regular/horner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace eve
//! @endcode
//!
//! 1. Polynom is evaluated at x the other inputs are the polynomial coefficients.
//! 2. Polynom is evaluated at x the other input is a range containing the coefficients
//! 2. Polynom is evaluated at x the other input is a range or a kumi::tuple containing the coefficients
//!
//! **Parameters**
//!
Expand All @@ -51,7 +51,7 @@ namespace eve
//! * `coefs...` : [real floating arguments](@ref eve::floating_ordered_value).
//! The coefficients by decreasing power order
//!
//! * `r` : Range containing The coefficients by decreasing power order.
//! * `r` : Range or kumi::tuple containing The coefficients by decreasing power order.
//!
//! **Return value**
//!
Expand Down
19 changes: 19 additions & 0 deletions include/eve/module/polynomial/regular/impl/horner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,23 @@ horner_(EVE_SUPPORTS(cpu_), T0 x, kumi::tuple<Ts...> tup) noexcept
return kumi::apply( [&](auto... m) { return horner(x, m...); }, tup);
}

//================================================================================================
//== Horner with ranges
//================================================================================================
template<value T0, range R>
EVE_FORCEINLINE constexpr auto
horner_(EVE_SUPPORTS(cpu_), T0 xx, R const& r) noexcept
requires(compatible_values<T0, typename R::value_type> && (!simd_value<R>))
{
return detail::horner_impl(regular_type(), xx, r);
}

template<value T0, range R>
EVE_FORCEINLINE constexpr auto
horner_(EVE_SUPPORTS(cpu_), compensated_type const&, T0 xx, R const& r) noexcept
requires(compatible_values<T0, typename R::value_type> && (!simd_value<R>))
{
return detail::horner_impl(compensated_type(), xx, r);
}

}
11 changes: 11 additions & 0 deletions include/eve/module/polynomial/regular/impl/reverse_horner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,15 @@ reverse_horner_(EVE_SUPPORTS(cpu_), D const & d, T0 x, kumi::tuple<Ts...> args)
return d(horner)(x, kumi::reverse(args));
}

//================================================================================================
//== reverse Horner with ranges
//================================================================================================
template<value T0, range R>
EVE_FORCEINLINE constexpr auto
reverse_horner_(EVE_SUPPORTS(cpu_), T0 xx, R const& r) noexcept
-> common_value_t<T0, typename R::value_type>
{
return detail::reverse_horner_impl(regular_type(), xx, r);
}

}
4 changes: 2 additions & 2 deletions include/eve/module/polynomial/regular/reverse_horner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ namespace eve
//! @endcode
//!
//! 1. Polynom is evaluated at x the other inputs are the polynomial coefficients.
//! 2. Polynom is evaluated at x the other input is a range containing the coefficients
//! 2. Polynom is evaluated at x the other input is a range or a kumi::tuple containing the coefficients
//!
//! **Parameters**
//!
//! * `x` : [real floating argument](@ref eve::floating_ordered_value).
//! * `coefs...` : [real floating arguments](@ref eve::floating_ordered_value).
//! The coefficients by increasing power order
//! * `r` : Range containing The coefficients by increasing power order.
//! * `r` : Range or kumi::tuplecontaining The coefficients by increasing power order.
//!
//! **Return value**
//!
Expand Down
Loading

0 comments on commit 32ff9be

Please sign in to comment.