1 // (C) Copyright John Maddock 2006.
2 // (C) Copyright Jeremy William Murphy 2015.
5 // Use, modification and distribution are subject to the
6 // Boost Software License, Version 1.0. (See accompanying file
7 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 #ifndef BOOST_MATH_TOOLS_POLYNOMIAL_HPP
10 #define BOOST_MATH_TOOLS_POLYNOMIAL_HPP
16 #include <boost/math/tools/assert.hpp>
17 #include <boost/math/tools/config.hpp>
18 #include <boost/math/tools/cxx03_warn.hpp>
19 #include <boost/math/tools/rational.hpp>
20 #include <boost/math/tools/real_cast.hpp>
21 #include <boost/math/policies/error_handling.hpp>
22 #include <boost/math/special_functions/binomial.hpp>
23 #include <boost/math/tools/detail/is_const_iterable.hpp>
28 #include <initializer_list>
29 #include <type_traits>
32 namespace boost{ namespace math{ namespace tools{
35 T chebyshev_coefficient(unsigned n, unsigned m)
40 if((n & 1) != (m & 1))
48 BOOST_MATH_ASSERT(n - 2 * r == m);
53 result *= boost::math::binomial_coefficient<T>(n - r, r);
54 result *= ldexp(1.0f, m);
59 Seq polynomial_to_chebyshev(const Seq& s)
61 // Converts a Polynomial into Chebyshev form:
62 typedef typename Seq::value_type value_type;
63 typedef typename Seq::difference_type difference_type;
65 difference_type order = s.size() - 1;
66 difference_type even_order = order & 1 ? order - 1 : order;
67 difference_type odd_order = order & 1 ? order : order - 1;
69 for(difference_type i = even_order; i >= 0; i -= 2)
71 value_type val = s[i];
72 for(difference_type k = even_order; k > i; k -= 2)
74 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
76 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
81 for(difference_type i = odd_order; i >= 0; i -= 2)
83 value_type val = s[i];
84 for(difference_type k = odd_order; k > i; k -= 2)
86 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
88 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
94 template <class Seq, class T>
95 T evaluate_chebyshev(const Seq& a, const T& x)
97 // Clenshaw's formula:
98 typedef typename Seq::difference_type difference_type;
102 for(difference_type i = a.size() - 1; i >= 1; --i)
106 yk = 2 * x * yk1 - yk2 + a[i];
108 return a[0] / 2 + yk * x - yk1;
112 template <typename T>
118 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
119 * Chapter 4.6.1, Algorithm D: Division of polynomials over a field.
121 * @tparam T Coefficient type, must be not be an integer.
123 * Template-parameter T actually must be a field but we don't currently have that
124 * subtlety of distinction.
126 template <typename T, typename N>
127 typename std::enable_if<!std::numeric_limits<T>::is_integer, void >::type
128 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
130 q[k] = u[n + k] / v[n];
131 for (N j = n + k; j > k;)
134 u[j] -= q[k] * v[j - k];
138 template <class T, class N>
139 T integer_power(T t, N n)
144 return static_cast<T>(1u);
152 T result = integer_power(t, n / 2);
161 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
162 * Chapter 4.6.1, Algorithm R: Pseudo-division of polynomials.
164 * @tparam T Coefficient type, must be an integer.
166 * Template-parameter T actually must be a unique factorization domain but we
167 * don't currently have that subtlety of distinction.
169 template <typename T, typename N>
170 typename std::enable_if<std::numeric_limits<T>::is_integer, void >::type
171 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
173 q[k] = u[n + k] * integer_power(v[n], k);
174 for (N j = n + k; j > 0;)
177 u[j] = v[n] * u[j] - (j < k ? T(0) : u[n + k] * v[j - k]);
183 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
184 * Chapter 4.6.1, Algorithm D and R: Main loop.
189 template <typename T>
190 std::pair< polynomial<T>, polynomial<T> >
191 division(polynomial<T> u, const polynomial<T>& v)
193 BOOST_MATH_ASSERT(v.size() <= u.size());
194 BOOST_MATH_ASSERT(v);
195 BOOST_MATH_ASSERT(u);
197 typedef typename polynomial<T>::size_type N;
199 N const m = u.size() - 1, n = v.size() - 1;
202 q.data().resize(m - n + 1);
206 division_impl(q, u, v, n, k);
210 u.normalize(); // Occasionally, the remainder is zeroes.
211 return std::make_pair(q, u);
215 // These structures are the same as the void specializations of the functors of the same name
216 // in the std lib from C++14 onwards:
221 T operator()(T const &x) const
229 template <class T, class U>
230 T operator()(T const &x, U const& y) const
238 template <class T, class U>
239 T operator()(T const &x, U const& y) const
245 } // namespace detail
248 * Returns the zero element for multiplication of polynomials.
251 polynomial<T> zero_element(std::multiplies< polynomial<T> >)
253 return polynomial<T>();
257 polynomial<T> identity_element(std::multiplies< polynomial<T> >)
259 return polynomial<T>(T(1));
262 /* Calculates a / b and a % b, returning the pair (quotient, remainder) together
263 * because the same amount of computation yields both.
264 * This function is not defined for division by zero: user beware.
266 template <typename T>
267 std::pair< polynomial<T>, polynomial<T> >
268 quotient_remainder(const polynomial<T>& dividend, const polynomial<T>& divisor)
270 BOOST_MATH_ASSERT(divisor);
271 if (dividend.size() < divisor.size())
272 return std::make_pair(polynomial<T>(), dividend);
273 return detail::division(dividend, divisor);
282 typedef typename std::vector<T>::value_type value_type;
283 typedef typename std::vector<T>::size_type size_type;
289 polynomial(const U* data, unsigned order)
290 : m_data(data, data + order + 1)
296 polynomial(I first, I last)
297 : m_data(first, last)
303 polynomial(I first, unsigned length)
304 : m_data(first, std::next(first, length + 1))
309 polynomial(std::vector<T>&& p) : m_data(std::move(p))
314 template <class U, typename std::enable_if<std::is_convertible<U, T>::value, bool>::type = true>
315 explicit polynomial(const U& point)
318 m_data.push_back(point);
322 polynomial(polynomial&& p) noexcept
323 : m_data(std::move(p.m_data)) { }
326 polynomial(const polynomial& p)
327 : m_data(p.m_data) { }
330 polynomial(const polynomial<U>& p)
332 m_data.resize(p.size());
333 for(unsigned i = 0; i < p.size(); ++i)
335 m_data[i] = boost::math::tools::real_cast<T>(p[i]);
338 #ifdef BOOST_MATH_HAS_IS_CONST_ITERABLE
339 template <class Range, typename std::enable_if<boost::math::tools::detail::is_const_iterable<Range>::value, bool>::type = true>
340 explicit polynomial(const Range& r)
341 : polynomial(r.begin(), r.end())
345 polynomial(std::initializer_list<T> l) : polynomial(std::begin(l), std::end(l))
350 operator=(std::initializer_list<T> l)
352 m_data.assign(std::begin(l), std::end(l));
359 size_type size() const { return m_data.size(); }
360 size_type degree() const
363 throw std::logic_error("degree() is undefined for the zero polynomial.");
364 return m_data.size() - 1;
366 value_type& operator[](size_type i)
370 const value_type& operator[](size_type i) const
375 T evaluate(T z) const
377 return this->operator()(z);
380 T operator()(T z) const
382 return m_data.size() > 0 ? boost::math::tools::evaluate_polynomial(&m_data[0], z, m_data.size()) : T(0);
384 std::vector<T> chebyshev() const
386 return polynomial_to_chebyshev(m_data);
389 std::vector<T> const& data() const
394 std::vector<T> & data()
399 polynomial<T> prime() const
402 // Disable int->float conversion warning:
403 #pragma warning(push)
404 #pragma warning(disable:4244)
406 if (m_data.size() == 0)
408 return polynomial<T>({});
411 std::vector<T> p_data(m_data.size() - 1);
412 for (size_t i = 0; i < p_data.size(); ++i) {
413 p_data[i] = m_data[i+1]*static_cast<T>(i+1);
415 return polynomial<T>(std::move(p_data));
421 polynomial<T> integrate() const
423 std::vector<T> i_data(m_data.size() + 1);
424 // Choose integration constant such that P(0) = 0.
426 for (size_t i = 1; i < i_data.size(); ++i)
428 i_data[i] = m_data[i-1]/static_cast<T>(i);
430 return polynomial<T>(std::move(i_data));
434 polynomial& operator =(polynomial&& p) noexcept
436 m_data = std::move(p.m_data);
440 polynomial& operator =(const polynomial& p)
447 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator +=(const U& value)
455 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator -=(const U& value)
463 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator *=(const U& value)
465 multiplication(value);
471 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator /=(const U& value)
479 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator %=(const U& /*value*/)
481 // We can always divide by a scalar, so there is no remainder:
487 polynomial& operator +=(const polynomial<U>& value)
495 polynomial& operator -=(const polynomial<U>& value)
502 template <typename U, typename V>
503 void multiply(const polynomial<U>& a, const polynomial<V>& b) {
509 std::vector<T> prod(a.size() + b.size() - 1, T(0));
510 for (unsigned i = 0; i < a.size(); ++i)
511 for (unsigned j = 0; j < b.size(); ++j)
512 prod[i+j] += a.m_data[i] * b.m_data[j];
517 polynomial& operator *=(const polynomial<U>& value)
519 this->multiply(*this, value);
523 template <typename U>
524 polynomial& operator /=(const polynomial<U>& value)
526 *this = quotient_remainder(*this, value).first;
530 template <typename U>
531 polynomial& operator %=(const polynomial<U>& value)
533 *this = quotient_remainder(*this, value).second;
537 template <typename U>
538 polynomial& operator >>=(U const &n)
540 BOOST_MATH_ASSERT(n <= m_data.size());
541 m_data.erase(m_data.begin(), m_data.begin() + n);
545 template <typename U>
546 polynomial& operator <<=(U const &n)
548 m_data.insert(m_data.begin(), n, static_cast<T>(0));
553 // Convenient and efficient query for zero.
556 return m_data.empty();
559 // Conversion to bool.
560 inline explicit operator bool() const
562 return !m_data.empty();
565 // Fast way to set a polynomial to zero.
571 /** Remove zero coefficients 'from the top', that is for which there are no
572 * non-zero coefficients of higher degree. */
575 m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), [](const T& x)->bool { return x != T(0); }).base(), m_data.end());
579 template <class U, class R>
580 polynomial& addition(const U& value, R op)
582 if(m_data.size() == 0)
584 m_data[0] = op(m_data[0], value);
589 polynomial& addition(const U& value)
591 return addition(value, detail::plus());
595 polynomial& subtraction(const U& value)
597 return addition(value, detail::minus());
600 template <class U, class R>
601 polynomial& addition(const polynomial<U>& value, R op)
603 if (m_data.size() < value.size())
604 m_data.resize(value.size(), 0);
605 for(size_type i = 0; i < value.size(); ++i)
606 m_data[i] = op(m_data[i], value[i]);
611 polynomial& addition(const polynomial<U>& value)
613 return addition(value, detail::plus());
617 polynomial& subtraction(const polynomial<U>& value)
619 return addition(value, detail::minus());
623 polynomial& multiplication(const U& value)
625 std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x * value; });
630 polynomial& division(const U& value)
632 std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x / value; });
636 std::vector<T> m_data;
641 inline polynomial<T> operator + (const polynomial<T>& a, const polynomial<T>& b)
643 polynomial<T> result(a);
649 inline polynomial<T> operator + (polynomial<T>&& a, const polynomial<T>& b)
655 inline polynomial<T> operator + (const polynomial<T>& a, polynomial<T>&& b)
661 inline polynomial<T> operator + (polynomial<T>&& a, polynomial<T>&& b)
668 inline polynomial<T> operator - (const polynomial<T>& a, const polynomial<T>& b)
670 polynomial<T> result(a);
676 inline polynomial<T> operator - (polynomial<T>&& a, const polynomial<T>& b)
682 inline polynomial<T> operator - (const polynomial<T>& a, polynomial<T>&& b)
688 inline polynomial<T> operator - (polynomial<T>&& a, polynomial<T>&& b)
695 inline polynomial<T> operator * (const polynomial<T>& a, const polynomial<T>& b)
697 polynomial<T> result;
698 result.multiply(a, b);
703 inline polynomial<T> operator / (const polynomial<T>& a, const polynomial<T>& b)
705 return quotient_remainder(a, b).first;
709 inline polynomial<T> operator % (const polynomial<T>& a, const polynomial<T>& b)
711 return quotient_remainder(a, b).second;
714 template <class T, class U>
715 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator + (polynomial<T> a, const U& b)
721 template <class T, class U>
722 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator - (polynomial<T> a, const U& b)
728 template <class T, class U>
729 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator * (polynomial<T> a, const U& b)
735 template <class T, class U>
736 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator / (polynomial<T> a, const U& b)
742 template <class T, class U>
743 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator % (const polynomial<T>&, const U&)
745 // Since we can always divide by a scalar, result is always an empty polynomial:
746 return polynomial<T>();
749 template <class U, class T>
750 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator + (const U& a, polynomial<T> b)
756 template <class U, class T>
757 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator - (const U& a, polynomial<T> b)
763 template <class U, class T>
764 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator * (const U& a, polynomial<T> b)
771 bool operator == (const polynomial<T> &a, const polynomial<T> &b)
773 return a.data() == b.data();
777 bool operator != (const polynomial<T> &a, const polynomial<T> &b)
779 return a.data() != b.data();
782 template <typename T, typename U>
783 polynomial<T> operator >> (polynomial<T> a, const U& b)
789 template <typename T, typename U>
790 polynomial<T> operator << (polynomial<T> a, const U& b)
796 // Unary minus (negate).
798 polynomial<T> operator - (polynomial<T> a)
800 std::transform(a.data().begin(), a.data().end(), a.data().begin(), detail::negate());
805 bool odd(polynomial<T> const &a)
807 return a.size() > 0 && a[0] != static_cast<T>(0);
811 bool even(polynomial<T> const &a)
817 polynomial<T> pow(polynomial<T> base, int exp)
820 return policies::raise_domain_error(
821 "boost::math::tools::pow<%1%>",
822 "Negative powers are not supported for polynomials.",
823 base, policies::policy<>());
824 // if the policy is ignore_error or errno_on_error, raise_domain_error
825 // will return std::numeric_limits<polynomial<T>>::quiet_NaN(), which
826 // defaults to polynomial<T>(), which is the zero polynomial
827 polynomial<T> result(T(1));
830 /* "Exponentiation by squaring" */
840 template <class charT, class traits, class T>
841 inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& os, const polynomial<T>& poly)
844 for(unsigned i = 0; i < poly.size(); ++i)
858 // Polynomial specific overload of gcd algorithm:
860 #include <boost/math/tools/polynomial_gcd.hpp>
862 #endif // BOOST_MATH_TOOLS_POLYNOMIAL_HPP