diff --git a/include/mvPolynomial/expression.hpp b/include/mvPolynomial/expression.hpp index 9c43a74..7adb029 100644 --- a/include/mvPolynomial/expression.hpp +++ b/include/mvPolynomial/expression.hpp @@ -1,8 +1,10 @@ #ifndef _MVPOLYNOMIAL_POLYNOMIAL_EXPRESSION_HPP_ #define _MVPOLYNOMIAL_POLYNOMIAL_EXPRESSION_HPP_ +#include #include #include +#include #include #include @@ -32,7 +34,7 @@ struct FilterRvalue { template requires is_const_ref_v || is_rvalue_v -class RefWrapper { +class RefWrapper final { using FilterResult = FilterRvalue; public: @@ -43,6 +45,14 @@ class RefWrapper { static constexpr bool is_rvalue = FilterResult::is_rvalue; + RefWrapper() = delete; + + RefWrapper(const RefWrapper&) = default; + RefWrapper(RefWrapper&&) = default; + RefWrapper& operator=(const RefWrapper&) = default; + RefWrapper& operator=(RefWrapper&&) = default; + ~RefWrapper() = default; + RefWrapper(T&& t) : t_(std::forward(t)) {} Range operator()(const Domain& x) const { return t_(x); } @@ -52,6 +62,7 @@ class RefWrapper { { return t_; } + const Storage& read() const requires(is_rvalue) { @@ -63,6 +74,7 @@ class RefWrapper { { return t_; } + Storage move() && requires(is_rvalue) { @@ -76,7 +88,7 @@ class RefWrapper { // L and R may be either const& or &&. template requires(is_const_ref_v || is_rvalue_v) && (is_const_ref_v || is_rvalue_v) -class BinaryExpr { +class BinaryExpr final { using LRef = RefWrapper; using RRef = RefWrapper; @@ -90,6 +102,14 @@ class BinaryExpr { static constexpr bool is_l_rvalue = LRef::is_rvalue; static constexpr bool is_r_rvalue = RRef::is_rvalue; + BinaryExpr() = delete; + + BinaryExpr(const BinaryExpr&) = default; + BinaryExpr(BinaryExpr&&) = default; + BinaryExpr& operator=(const BinaryExpr&) = default; + BinaryExpr& operator=(BinaryExpr&&) = default; + ~BinaryExpr() = default; + BinaryExpr(L&& l, R&& r) : l_(std::forward(l)), r_(std::forward(r)) {} // Calculate x of this @@ -173,7 +193,7 @@ struct Multiply { // F and G may be either const& or &&. template requires(is_const_ref_v || is_rvalue_v) && (is_const_ref_v || is_rvalue_v) -class Composition { +class Composition final { using FRef = RefWrapper; using GRef = RefWrapper; @@ -186,9 +206,17 @@ class Composition { static constexpr bool is_outer_rvalue = FRef::is_rvalue; static constexpr bool is_inner_rvalue = GRef::is_rvalue; + Composition() = delete; + + Composition(const Composition&) = default; + Composition(Composition&&) = default; + Composition& operator=(const Composition&) = default; + Composition& operator=(Composition&&) = default; + ~Composition() = default; + Composition(F&& f, G&& g) : f_(std::forward(f)), g_(std::forward(g)) {} - Range operator()(const Domain& x) { return f_(g_(x)); } + Range operator()(const Domain& x) const { return f_(g_(x)); } const auto& read_outer() const { return f_.read(); } @@ -223,6 +251,62 @@ class Composition { GRef g_; }; +template +requires is_const_ref_v || is_rvalue_v +class Power { + using FRef = RefWrapper; + + public: + using Domain = typename F::Domain; + using Range = typename F::Range; + + static constexpr bool is_base_rvalue = FRef::is_rvalue; + + Power() = delete; + + Power(const Power&) = default; + Power(Power&&) = default; + Power& operator=(const Power&) = default; + Power& operator=(Power&&) = default; + ~Power() = default; + + Power(F&& f, int exp) : f_(std::forward(f)), exp_(exp) { + if (exp < 0) { + throw std::invalid_argument("Exponent must be non-negative!"); + } + } + + Range operator()(const Domain& x) const + requires(std::is_floating_point_v) + { + return std::pow(f_(x), exp_); + } + Range operator()(const Domain& x) const + requires(!std::is_floating_point_v) + { + return Pow(f_(x), exp_); + } + + const auto& read_base() const { return f_.read(); } + int read_expo() const { return exp_; } + + auto move_base() + requires(is_base_rvalue) + { + return std::move(f_).move(); + } + + decltype(auto) move_base() + requires(!is_base_rvalue) + { + return std::move(f_).move(); + } + + private: + FRef f_; + int exp_; +}; + template auto D(int axis, BinaryExpr&& expr) { auto d_l = D(axis, expr.move_l()); @@ -299,6 +383,30 @@ auto D(int axis, const Composition& comp) { }; } +template +auto D(int axis, Power&& pow_f) { + auto d_f = D(axis, pow_f.read_base()); + return BinaryExpr&&>, Multiply, decltype(d_f)&&>{ + BinaryExpr&&>{ + pow_f.read_expo(), + Power{pow_f.move_base(), pow_f.read_expo() - 1}, + }, + std::move(d_f) + }; +} + +template +auto D(int axis, const Power& pow_f) { + auto d_f = D(axis, pow_f.read_base()); + return BinaryExpr&>, Multiply, decltype(d_f)&&>{ + BinaryExpr&>{ + pow_f.read_expo(), + Power{pow_f.read_base(), pow_f.read_expo() - 1}, + }, + std::move(d_f) + }; +} + template auto S(std::size_t axis, B&& begin, E&& end, BinaryExpr&& expr) { auto s_l = S(axis, std::forward(begin), std::forward(end), expr.move_l());