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/assert.hpp>
17 #include <boost/config.hpp>
18 #ifdef BOOST_NO_CXX11_LAMBDAS
19 #include <boost/lambda/lambda.hpp>
21 #include <boost/math/tools/rational.hpp>
22 #include <boost/math/tools/real_cast.hpp>
23 #include <boost/math/policies/error_handling.hpp>
24 #include <boost/math/special_functions/binomial.hpp>
25 #include <boost/core/enable_if.hpp>
30 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
31 #include <initializer_list>
34 namespace boost{ namespace math{ namespace tools{
37 T chebyshev_coefficient(unsigned n, unsigned m)
42 if((n & 1) != (m & 1))
50 BOOST_ASSERT(n - 2 * r == m);
55 result *= boost::math::binomial_coefficient<T>(n - r, r);
56 result *= ldexp(1.0f, m);
61 Seq polynomial_to_chebyshev(const Seq& s)
63 // Converts a Polynomial into Chebyshev form:
64 typedef typename Seq::value_type value_type;
65 typedef typename Seq::difference_type difference_type;
67 difference_type order = s.size() - 1;
68 difference_type even_order = order & 1 ? order - 1 : order;
69 difference_type odd_order = order & 1 ? order : order - 1;
71 for(difference_type i = even_order; i >= 0; i -= 2)
73 value_type val = s[i];
74 for(difference_type k = even_order; k > i; k -= 2)
76 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
78 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
83 for(difference_type i = odd_order; i >= 0; i -= 2)
85 value_type val = s[i];
86 for(difference_type k = odd_order; k > i; k -= 2)
88 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
90 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
96 template <class Seq, class T>
97 T evaluate_chebyshev(const Seq& a, const T& x)
99 // Clenshaw's formula:
100 typedef typename Seq::difference_type difference_type;
104 for(difference_type i = a.size() - 1; i >= 1; --i)
108 yk = 2 * x * yk1 - yk2 + a[i];
110 return a[0] / 2 + yk * x - yk1;
114 template <typename T>
120 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
121 * Chapter 4.6.1, Algorithm D: Division of polynomials over a field.
123 * @tparam T Coefficient type, must be not be an integer.
125 * Template-parameter T actually must be a field but we don't currently have that
126 * subtlety of distinction.
128 template <typename T, typename N>
129 BOOST_DEDUCED_TYPENAME disable_if_c<std::numeric_limits<T>::is_integer, void >::type
130 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
132 q[k] = u[n + k] / v[n];
133 for (N j = n + k; j > k;)
136 u[j] -= q[k] * v[j - k];
140 template <class T, class N>
141 T integer_power(T t, N n)
146 return static_cast<T>(1u);
154 T result = integer_power(t, n / 2);
163 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
164 * Chapter 4.6.1, Algorithm R: Pseudo-division of polynomials.
166 * @tparam T Coefficient type, must be an integer.
168 * Template-parameter T actually must be a unique factorization domain but we
169 * don't currently have that subtlety of distinction.
171 template <typename T, typename N>
172 BOOST_DEDUCED_TYPENAME enable_if_c<std::numeric_limits<T>::is_integer, void >::type
173 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
175 q[k] = u[n + k] * integer_power(v[n], k);
176 for (N j = n + k; j > 0;)
179 u[j] = v[n] * u[j] - (j < k ? T(0) : u[n + k] * v[j - k]);
185 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
186 * Chapter 4.6.1, Algorithm D and R: Main loop.
191 template <typename T>
192 std::pair< polynomial<T>, polynomial<T> >
193 division(polynomial<T> u, const polynomial<T>& v)
195 BOOST_ASSERT(v.size() <= u.size());
199 typedef typename polynomial<T>::size_type N;
201 N const m = u.size() - 1, n = v.size() - 1;
204 q.data().resize(m - n + 1);
208 division_impl(q, u, v, n, k);
212 u.normalize(); // Occasionally, the remainder is zeroes.
213 return std::make_pair(q, u);
219 const T& operator()(T const &x) const
225 // These structures are the same as the void specializations of the functors of the same name
226 // in the std lib from C++14 onwards:
231 T operator()(T const &x) const
239 template <class T, class U>
240 T operator()(T const &x, U const& y) const
248 template <class T, class U>
249 T operator()(T const &x, U const& y) const
255 } // namespace detail
258 * Returns the zero element for multiplication of polynomials.
261 polynomial<T> zero_element(std::multiplies< polynomial<T> >)
263 return polynomial<T>();
267 polynomial<T> identity_element(std::multiplies< polynomial<T> >)
269 return polynomial<T>(T(1));
272 /* Calculates a / b and a % b, returning the pair (quotient, remainder) together
273 * because the same amount of computation yields both.
274 * This function is not defined for division by zero: user beware.
276 template <typename T>
277 std::pair< polynomial<T>, polynomial<T> >
278 quotient_remainder(const polynomial<T>& dividend, const polynomial<T>& divisor)
280 BOOST_ASSERT(divisor);
281 if (dividend.size() < divisor.size())
282 return std::make_pair(polynomial<T>(), dividend);
283 return detail::division(dividend, divisor);
292 typedef typename std::vector<T>::value_type value_type;
293 typedef typename std::vector<T>::size_type size_type;
299 polynomial(const U* data, unsigned order)
300 : m_data(data, data + order + 1)
306 polynomial(I first, I last)
307 : m_data(first, last)
313 explicit polynomial(const U& point)
316 m_data.push_back(point);
319 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
321 polynomial(polynomial&& p) BOOST_NOEXCEPT
322 : 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 for(unsigned i = 0; i < p.size(); ++i)
334 m_data.push_back(boost::math::tools::real_cast<T>(p[i]));
338 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40500)
339 polynomial(std::initializer_list<T> l) : polynomial(std::begin(l), std::end(l))
344 operator=(std::initializer_list<T> l)
346 m_data.assign(std::begin(l), std::end(l));
354 size_type size() const { return m_data.size(); }
355 size_type degree() const
358 throw std::logic_error("degree() is undefined for the zero polynomial.");
359 return m_data.size() - 1;
361 value_type& operator[](size_type i)
365 const value_type& operator[](size_type i) const
369 T evaluate(T z) const
371 return m_data.size() > 0 ? boost::math::tools::evaluate_polynomial(&m_data[0], z, m_data.size()) : 0;
373 std::vector<T> chebyshev() const
375 return polynomial_to_chebyshev(m_data);
378 std::vector<T> const& data() const
383 std::vector<T> & data()
389 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
390 polynomial& operator =(polynomial&& p) BOOST_NOEXCEPT
392 m_data = std::move(p.m_data);
396 polynomial& operator =(const polynomial& p)
403 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator +=(const U& value)
411 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator -=(const U& value)
419 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator *=(const U& value)
421 multiplication(value);
427 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator /=(const U& value)
435 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator %=(const U& /*value*/)
437 // We can always divide by a scalar, so there is no remainder:
443 polynomial& operator +=(const polynomial<U>& value)
451 polynomial& operator -=(const polynomial<U>& value)
458 template <typename U, typename V>
459 void multiply(const polynomial<U>& a, const polynomial<V>& b) {
465 std::vector<T> prod(a.size() + b.size() - 1, T(0));
466 for (unsigned i = 0; i < a.size(); ++i)
467 for (unsigned j = 0; j < b.size(); ++j)
468 prod[i+j] += a.m_data[i] * b.m_data[j];
473 polynomial& operator *=(const polynomial<U>& value)
475 this->multiply(*this, value);
479 template <typename U>
480 polynomial& operator /=(const polynomial<U>& value)
482 *this = quotient_remainder(*this, value).first;
486 template <typename U>
487 polynomial& operator %=(const polynomial<U>& value)
489 *this = quotient_remainder(*this, value).second;
493 template <typename U>
494 polynomial& operator >>=(U const &n)
496 BOOST_ASSERT(n <= m_data.size());
497 m_data.erase(m_data.begin(), m_data.begin() + n);
501 template <typename U>
502 polynomial& operator <<=(U const &n)
504 m_data.insert(m_data.begin(), n, static_cast<T>(0));
509 // Convenient and efficient query for zero.
512 return m_data.empty();
515 // Conversion to bool.
516 #ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
517 typedef bool (polynomial::*unmentionable_type)() const;
519 BOOST_FORCEINLINE operator unmentionable_type() const
521 return is_zero() ? false : &polynomial::is_zero;
524 BOOST_FORCEINLINE explicit operator bool() const
526 return !m_data.empty();
530 // Fast way to set a polynomial to zero.
536 /** Remove zero coefficients 'from the top', that is for which there are no
537 * non-zero coefficients of higher degree. */
540 #ifndef BOOST_NO_CXX11_LAMBDAS
541 m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), [](const T& x)->bool { return x != 0; }).base(), m_data.end());
543 using namespace boost::lambda;
544 m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), _1 != T(0)).base(), m_data.end());
549 template <class U, class R1, class R2>
550 polynomial& addition(const U& value, R1 sign, R2 op)
552 if(m_data.size() == 0)
553 m_data.push_back(sign(value));
555 m_data[0] = op(m_data[0], value);
560 polynomial& addition(const U& value)
562 return addition(value, detail::identity(), detail::plus());
566 polynomial& subtraction(const U& value)
568 return addition(value, detail::negate(), detail::minus());
571 template <class U, class R1, class R2>
572 polynomial& addition(const polynomial<U>& value, R1 sign, R2 op)
574 size_type s1 = (std::min)(m_data.size(), value.size());
575 for(size_type i = 0; i < s1; ++i)
576 m_data[i] = op(m_data[i], value[i]);
577 for(size_type i = s1; i < value.size(); ++i)
578 m_data.push_back(sign(value[i]));
583 polynomial& addition(const polynomial<U>& value)
585 return addition(value, detail::identity(), detail::plus());
589 polynomial& subtraction(const polynomial<U>& value)
591 return addition(value, detail::negate(), detail::minus());
595 polynomial& multiplication(const U& value)
597 #ifndef BOOST_NO_CXX11_LAMBDAS
598 std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x * value; });
600 using namespace boost::lambda;
601 std::transform(m_data.begin(), m_data.end(), m_data.begin(), ret<T>(_1 * value));
607 polynomial& division(const U& value)
609 #ifndef BOOST_NO_CXX11_LAMBDAS
610 std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x / value; });
612 using namespace boost::lambda;
613 std::transform(m_data.begin(), m_data.end(), m_data.begin(), ret<T>(_1 / value));
618 std::vector<T> m_data;
623 inline polynomial<T> operator + (const polynomial<T>& a, const polynomial<T>& b)
625 polynomial<T> result(a);
629 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
631 inline polynomial<T> operator + (polynomial<T>&& a, const polynomial<T>& b)
637 inline polynomial<T> operator + (const polynomial<T>& a, polynomial<T>&& b)
643 inline polynomial<T> operator + (polynomial<T>&& a, polynomial<T>&& b)
651 inline polynomial<T> operator - (const polynomial<T>& a, const polynomial<T>& b)
653 polynomial<T> result(a);
657 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
659 inline polynomial<T> operator - (polynomial<T>&& a, const polynomial<T>& b)
665 inline polynomial<T> operator - (const polynomial<T>& a, polynomial<T>&& b)
671 inline polynomial<T> operator - (polynomial<T>&& a, polynomial<T>&& b)
679 inline polynomial<T> operator * (const polynomial<T>& a, const polynomial<T>& b)
681 polynomial<T> result;
682 result.multiply(a, b);
687 inline polynomial<T> operator / (const polynomial<T>& a, const polynomial<T>& b)
689 return quotient_remainder(a, b).first;
693 inline polynomial<T> operator % (const polynomial<T>& a, const polynomial<T>& b)
695 return quotient_remainder(a, b).second;
698 template <class T, class U>
699 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator + (polynomial<T> a, const U& b)
705 template <class T, class U>
706 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator - (polynomial<T> a, const U& b)
712 template <class T, class U>
713 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator * (polynomial<T> a, const U& b)
719 template <class T, class U>
720 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator / (polynomial<T> a, const U& b)
726 template <class T, class U>
727 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator % (const polynomial<T>&, const U&)
729 // Since we can always divide by a scalar, result is always an empty polynomial:
730 return polynomial<T>();
733 template <class U, class T>
734 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator + (const U& a, polynomial<T> b)
740 template <class U, class T>
741 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator - (const U& a, polynomial<T> b)
747 template <class U, class T>
748 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator * (const U& a, polynomial<T> b)
755 bool operator == (const polynomial<T> &a, const polynomial<T> &b)
757 return a.data() == b.data();
761 bool operator != (const polynomial<T> &a, const polynomial<T> &b)
763 return a.data() != b.data();
766 template <typename T, typename U>
767 polynomial<T> operator >> (polynomial<T> a, const U& b)
773 template <typename T, typename U>
774 polynomial<T> operator << (polynomial<T> a, const U& b)
780 // Unary minus (negate).
782 polynomial<T> operator - (polynomial<T> a)
784 std::transform(a.data().begin(), a.data().end(), a.data().begin(), detail::negate());
789 bool odd(polynomial<T> const &a)
791 return a.size() > 0 && a[0] != static_cast<T>(0);
795 bool even(polynomial<T> const &a)
801 polynomial<T> pow(polynomial<T> base, int exp)
804 return policies::raise_domain_error(
805 "boost::math::tools::pow<%1%>",
806 "Negative powers are not supported for polynomials.",
807 base, policies::policy<>());
808 // if the policy is ignore_error or errno_on_error, raise_domain_error
809 // will return std::numeric_limits<polynomial<T>>::quiet_NaN(), which
810 // defaults to polynomial<T>(), which is the zero polynomial
811 polynomial<T> result(T(1));
814 /* "Exponentiation by squaring" */
824 template <class charT, class traits, class T>
825 inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& os, const polynomial<T>& poly)
828 for(unsigned i = 0; i < poly.size(); ++i)
842 // Polynomial specific overload of gcd algorithm:
844 #include <boost/math/tools/polynomial_gcd.hpp>
846 #endif // BOOST_MATH_TOOLS_POLYNOMIAL_HPP