Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 89 additions & 154 deletions poly.h
Original file line number Diff line number Diff line change
@@ -1,78 +1,32 @@
#ifndef POLY_H
#define POLY_H
#endif

#include <array>
#include <iostream>
#include <type_traits>
#include <utility>
#include <sstream>

#define DEBUG 1

#if DEBUG
#define DBG_PRINT(x) \
if (!std::is_constant_evaluated()) { \
std::cout << x << std::endl; \
}
#else
#define DBG_PRINT(x)
#endif

template <typename U, typename T, std::size_t M, std::size_t N>
concept PolyConvertible = (M <= N) && std::is_convertible_v<U, T>;

// To be able to use the "poly" type name before its definition
// To be able to use the "poly" type name before its definition.
template <typename T, std::size_t N> class poly;

// For recursive deduction of the base type of poly<...>.
template <typename T>
struct BaseType {
template <typename T> struct BaseType {
using type = T;
};
template <typename T, std::size_t N>
struct BaseType<poly<T, N>> {
template <typename T, std::size_t N> struct BaseType<poly<T, N>> {
using type = typename BaseType<T>::type;
};
template <typename T>
using base_type = typename BaseType<T>::type;
template <typename T> using base_type = typename BaseType<T>::type;

template <typename T, std::size_t N = 0> class poly {

private:
std::array<T, N> coefs{};

std::ostringstream oss(int var) const {
std::ostringstream res;
for (std::size_t i = 0; i < N; ++i) {
const T& a = this->coefs[i];
if constexpr (requires { typename T::value_type; }) {
res << "(" << a.oss(var+1).str() << ")";
}
else {
res << a;
}
if (i > 0) {
res << "*x" << var;
}
if (i > 1) {
res << "^" << i;
}
if (i < N-1) {
res << " + ";
}
}
return res;
}

public:
std::string to_string() const {
return this->oss(1).str();
}

friend std::ostream& operator<<(std::ostream& os, const poly& p) {
return os << "poly<" << typeid(T).name() << ", " << N << ">";
}

constexpr poly() = default;

template <typename U, std::size_t M>
Expand All @@ -99,9 +53,10 @@ template <typename T, std::size_t N = 0> class poly {
}

template <typename... Args>
requires(sizeof...(Args) >= 2 && sizeof...(Args) <= N && (std::convertible_to<Args, T> && ...))
constexpr poly(Args&&... args) : coefs{static_cast<T>(std::forward<Args>(args))...} {
}
requires(sizeof...(Args) >= 2 && sizeof...(Args) <= N &&
(std::convertible_to<Args, T> && ...))
constexpr poly(Args&&... args)
: coefs{static_cast<T>(std::forward<Args>(args))...} {}

constexpr std::size_t size() const { return N; }

Expand Down Expand Up @@ -212,7 +167,7 @@ template <typename T, std::size_t N = 0> class poly {
return result;
}

// Multiplication of a poly object with a scalar
// Multiplication of a poly object with a scalar.
template <typename U>
requires std::convertible_to<U, T>
constexpr auto operator*(const U& value) const {
Expand All @@ -223,7 +178,7 @@ template <typename T, std::size_t N = 0> class poly {
return result;
}

// Addition of a poly object with a scalar
// Addition of a poly object with a scalar.
template <typename U>
requires std::convertible_to<U, T>
constexpr auto operator+(const U& value) const {
Expand All @@ -232,7 +187,7 @@ template <typename T, std::size_t N = 0> class poly {
return result;
}

// Subtraction of a poly object with a scalar
// Subtraction of a poly object with a scalar.
template <typename U>
requires std::convertible_to<U, T>
constexpr auto operator-(const U& value) const {
Expand All @@ -242,120 +197,101 @@ template <typename T, std::size_t N = 0> class poly {
}

template <typename U>
requires std::convertible_to<U, T>
static constexpr std::common_type_t<T, U> eval_term(const T& coef, const U& pow_base, std::size_t pow_exp) {
std::common_type_t<T, U> res = coef;
for (std::size_t i = 1; i <= pow_exp; ++i) {
res *= pow_base;
}
return res;
}

constexpr const poly<T, N>& at() const {
return *this;
requires std::convertible_to<U, T>
static constexpr U eval_term(const T& coef, const U& pow_base,
std::size_t pow_exp) {
U res = coef;
for (std::size_t i = 1; i <= pow_exp; ++i) {
res *= pow_base;
}
return res;
}

template <typename U>
requires std::convertible_to<U, T>
constexpr std::common_type_t<T, U> at(const U& arg) const {
if (N == 0) {
return T{};
}

std::common_type_t<T, U> res = this->coefs[0];

for (std::size_t i = 1; i < N; ++i) {
std::common_type_t<T, U> term = eval_term(this->coefs[i], arg, i);
res += term;
}

return res;
}
constexpr const poly<T, N>& at() const { return *this; }

template <typename U>
requires std::convertible_to<U, T>
constexpr auto at(const U& arg) const {
using R = decltype(coefs[0] * arg);
if (N == 0) {
return R{};
}

R res = coefs[N - 1];

for (std::size_t i = N - 1; i > 0; --i) {
res = res * arg + coefs[i - 1];
}

return res;
}

template <typename U, std::size_t M>
requires std::convertible_to<base_type<U>, T>
requires std::convertible_to<base_type<U>, T>
constexpr auto at(const poly<U, M>& arg) const {
constexpr std::size_t res_size = (N-1)*(M-1) + 1;
constexpr std::size_t res_size = (N - 1) * (M - 1) + 1;
using res_type = poly<std::common_type_t<T, U>, res_size>;

if (N == 0) {
return res_type();
}
return res_type();
}
res_type res(this->coefs[0]);

for (std::size_t i = 1; i < N; ++i) {
res_type term(arg);

for (std::size_t exp = 1; exp < i; ++exp) {
res_type temp_result{};
for (std::size_t k = 0; k < term.size(); ++k) {
for (std::size_t j = 0; j < arg.size(); ++j) {
if (k + j < temp_result.size()) {
temp_result[k + j] += term[k] * arg[j];
}
}
}
term = temp_result;
}

for (std::size_t k = 0; k < term.size(); ++k) {
term[k] *= this->coefs[i];
}

res += term;
}

return res;
}

template <typename U, typename... Args>
constexpr auto at(const U& first, Args&&... args) const
requires (std::convertible_to<base_type<U>, T> && (std::convertible_to<base_type<Args>, T> && ...)) {
if (N <= 1) {
return this->at(first);
}

using result_type = decltype(this->coefs[0].at(args...));
result_type result = this->coefs[0].at(args...);

for (std::size_t i = 1; i < N; ++i) {
result += this->coefs[i].at(args...) * pow(first, i);
}

return result;
}

template <typename P, typename U, std::size_t K>
static constexpr auto at_array(const P& p, const std::array<U, K>& arr) {
return at_array_impl(p, arr, std::make_index_sequence<K>{});
}

template <typename P, typename U, std::size_t K, std::size_t... Is>
static constexpr auto at_array_impl(const P& p, const std::array<U, K>& arr, std::index_sequence<Is...>) {
return p.at(arr[Is]...);
for (std::size_t i = N - 1; i > 0; --i) {
res = res * arg + res_type(this->coefs[i - 1]);
/*res_type term(arg);

for (std::size_t exp = 1; exp < i; ++exp) {
res_type temp_result{};
for (std::size_t k = 0; k < term.size(); ++k) {
for (std::size_t j = 0; j < arg.size(); ++j) {
if (k + j < temp_result.size()) {
temp_result[k + j] += term[k] * arg[j];
}
}
}
term = temp_result;
}

for (std::size_t k = 0; k < term.size(); ++k) {
term[k] *= this->coefs[i];
}

res += term;*/
}

return res;
}

template <typename U, std::size_t K>
constexpr auto at(const std::array<U, K>& arr) const {
return at_array(*this, arr);

template <typename A, typename... Args>
constexpr auto at(const A& a, const Args&... rest) const {
using R = decltype(this->coefs[0].at(rest...) * a);
if (N == 0) {
return R{};
}
R res = coefs[N-1].at(rest...);
for (std::size_t i = N - 1; i > 0; --i) {
res = res * a + this->coefs[i - 1].at(rest...);
}
return res;
}
};

// Non-member operator* for scalar multiplication.
// Non-member operator* for scalar multiplication.
template <typename T, std::size_t N, typename U>
requires std::convertible_to<U, T>
constexpr auto operator*(const U& value, const poly<T, N>& p) {
return p * value;
}

// Non-member operator+ for scalar addition.
// Non-member operator+ for scalar addition.
template <typename T, std::size_t N, typename U>
requires std::convertible_to<U, T>
constexpr auto operator+(const U& value, const poly<T, N>& p) {
return p + value;
}

// Non-member operator- for scalar subtraction.
// Non-member operator- for scalar subtraction.
template <typename T, std::size_t N, typename U>
requires std::convertible_to<U, T>
constexpr auto operator-(const U& value, const poly<T, N>& p) {
Expand All @@ -364,21 +300,19 @@ constexpr auto operator-(const U& value, const poly<T, N>& p) {

template <typename U, std::size_t M>
constexpr auto const_poly(const poly<U, M>& p) {
DBG_PRINT("const_poly constructor called");
return poly<poly<U, M>, 1>{p};
}

namespace detail {

template <typename T> struct is_poly_impl : std::false_type {};

template <typename T, std::size_t N>
struct is_poly_impl<poly<T, N>> : std::true_type {};

template <typename T>
struct is_poly : is_poly_impl<std::remove_cvref_t<T>> {};
template <typename T> struct is_poly : is_poly_impl<std::remove_cvref_t<T>> {};

template <typename T>
inline constexpr bool is_poly_v = is_poly<T>::value;
template <typename T> inline constexpr bool is_poly_v = is_poly<T>::value;
} // namespace detail

// std::common_type specialization for poly.
Expand All @@ -390,17 +324,16 @@ struct common_type<poly<T, N>, poly<U, M>> {
};

template <typename T, std::size_t N, typename U>
requires (!detail::is_poly_v<U>)
requires(!detail::is_poly_v<U>)
struct common_type<poly<T, N>, U> {
using type = poly<std::common_type_t<T, U>, N>;
};

template <typename T, typename U, std::size_t M>
requires (!detail::is_poly_v<T>)
requires(!detail::is_poly_v<T>)
struct common_type<T, poly<U, M>> {
using type = poly<std::common_type_t<T, U>, M>;
};

} // namespace std

template <typename T, typename... Args>
Expand Down Expand Up @@ -439,3 +372,5 @@ template <typename T1, typename T2>
constexpr auto cross(const T1& a, const T2& b) {
return a * b;
}

#endif // POLY_H