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 #include <boost/math/tools/cxx03_warn.hpp>
19 #ifdef BOOST_NO_CXX11_LAMBDAS
20 #include <boost/lambda/lambda.hpp>
22 #include <boost/math/tools/rational.hpp>
23 #include <boost/math/tools/real_cast.hpp>
24 #include <boost/math/policies/error_handling.hpp>
25 #include <boost/math/special_functions/binomial.hpp>
26 #include <boost/core/enable_if.hpp>
27 #include <boost/type_traits/is_convertible.hpp>
28 #include <boost/math/tools/detail/is_const_iterable.hpp>
33 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
34 #include <initializer_list>
37 namespace boost{ namespace math{ namespace tools{
40 T chebyshev_coefficient(unsigned n, unsigned m)
45 if((n & 1) != (m & 1))
53 BOOST_ASSERT(n - 2 * r == m);
58 result *= boost::math::binomial_coefficient<T>(n - r, r);
59 result *= ldexp(1.0f, m);
64 Seq polynomial_to_chebyshev(const Seq& s)
66 // Converts a Polynomial into Chebyshev form:
67 typedef typename Seq::value_type value_type;
68 typedef typename Seq::difference_type difference_type;
70 difference_type order = s.size() - 1;
71 difference_type even_order = order & 1 ? order - 1 : order;
72 difference_type odd_order = order & 1 ? order : order - 1;
74 for(difference_type i = even_order; i >= 0; i -= 2)
76 value_type val = s[i];
77 for(difference_type k = even_order; k > i; k -= 2)
79 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
81 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
86 for(difference_type i = odd_order; i >= 0; i -= 2)
88 value_type val = s[i];
89 for(difference_type k = odd_order; k > i; k -= 2)
91 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
93 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
99 template <class Seq, class T>
100 T evaluate_chebyshev(const Seq& a, const T& x)
102 // Clenshaw's formula:
103 typedef typename Seq::difference_type difference_type;
107 for(difference_type i = a.size() - 1; i >= 1; --i)
111 yk = 2 * x * yk1 - yk2 + a[i];
113 return a[0] / 2 + yk * x - yk1;
117 template <typename T>
123 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
124 * Chapter 4.6.1, Algorithm D: Division of polynomials over a field.
126 * @tparam T Coefficient type, must be not be an integer.
128 * Template-parameter T actually must be a field but we don't currently have that
129 * subtlety of distinction.
131 template <typename T, typename N>
132 BOOST_DEDUCED_TYPENAME disable_if_c<std::numeric_limits<T>::is_integer, void >::type
133 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
135 q[k] = u[n + k] / v[n];
136 for (N j = n + k; j > k;)
139 u[j] -= q[k] * v[j - k];
143 template <class T, class N>
144 T integer_power(T t, N n)
149 return static_cast<T>(1u);
157 T result = integer_power(t, n / 2);
166 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
167 * Chapter 4.6.1, Algorithm R: Pseudo-division of polynomials.
169 * @tparam T Coefficient type, must be an integer.
171 * Template-parameter T actually must be a unique factorization domain but we
172 * don't currently have that subtlety of distinction.
174 template <typename T, typename N>
175 BOOST_DEDUCED_TYPENAME enable_if_c<std::numeric_limits<T>::is_integer, void >::type
176 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
178 q[k] = u[n + k] * integer_power(v[n], k);
179 for (N j = n + k; j > 0;)
182 u[j] = v[n] * u[j] - (j < k ? T(0) : u[n + k] * v[j - k]);
188 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
189 * Chapter 4.6.1, Algorithm D and R: Main loop.
194 template <typename T>
195 std::pair< polynomial<T>, polynomial<T> >
196 division(polynomial<T> u, const polynomial<T>& v)
198 BOOST_ASSERT(v.size() <= u.size());
202 typedef typename polynomial<T>::size_type N;
204 N const m = u.size() - 1, n = v.size() - 1;
207 q.data().resize(m - n + 1);
211 division_impl(q, u, v, n, k);
215 u.normalize(); // Occasionally, the remainder is zeroes.
216 return std::make_pair(q, u);
220 // These structures are the same as the void specializations of the functors of the same name
221 // in the std lib from C++14 onwards:
226 T operator()(T const &x) const
234 template <class T, class U>
235 T operator()(T const &x, U const& y) const
243 template <class T, class U>
244 T operator()(T const &x, U const& y) const
250 } // namespace detail
253 * Returns the zero element for multiplication of polynomials.
256 polynomial<T> zero_element(std::multiplies< polynomial<T> >)
258 return polynomial<T>();
262 polynomial<T> identity_element(std::multiplies< polynomial<T> >)
264 return polynomial<T>(T(1));
267 /* Calculates a / b and a % b, returning the pair (quotient, remainder) together
268 * because the same amount of computation yields both.
269 * This function is not defined for division by zero: user beware.
271 template <typename T>
272 std::pair< polynomial<T>, polynomial<T> >
273 quotient_remainder(const polynomial<T>& dividend, const polynomial<T>& divisor)
275 BOOST_ASSERT(divisor);
276 if (dividend.size() < divisor.size())
277 return std::make_pair(polynomial<T>(), dividend);
278 return detail::division(dividend, divisor);
287 typedef typename std::vector<T>::value_type value_type;
288 typedef typename std::vector<T>::size_type size_type;
294 polynomial(const U* data, unsigned order)
295 : m_data(data, data + order + 1)
301 polynomial(I first, I last)
302 : m_data(first, last)
307 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
308 polynomial(std::vector<T>&& p) : m_data(std::move(p))
315 explicit polynomial(const U& point, typename boost::enable_if<boost::is_convertible<U, T> >::type* = 0)
318 m_data.push_back(point);
321 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
323 polynomial(polynomial&& p) BOOST_NOEXCEPT
324 : m_data(std::move(p.m_data)) { }
328 polynomial(const polynomial& p)
329 : m_data(p.m_data) { }
332 polynomial(const polynomial<U>& p)
334 m_data.resize(p.size());
335 for(unsigned i = 0; i < p.size(); ++i)
337 m_data[i] = boost::math::tools::real_cast<T>(p[i]);
340 #ifdef BOOST_MATH_HAS_IS_CONST_ITERABLE
341 template <class Range>
342 explicit polynomial(const Range& r, typename boost::enable_if<boost::math::tools::detail::is_const_iterable<Range> >::type* = 0)
343 : polynomial(r.begin(), r.end())
347 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40500)
348 polynomial(std::initializer_list<T> l) : polynomial(std::begin(l), std::end(l))
353 operator=(std::initializer_list<T> l)
355 m_data.assign(std::begin(l), std::end(l));
363 size_type size() const { return m_data.size(); }
364 size_type degree() const
367 throw std::logic_error("degree() is undefined for the zero polynomial.");
368 return m_data.size() - 1;
370 value_type& operator[](size_type i)
374 const value_type& operator[](size_type i) const
379 T evaluate(T z) const
381 return this->operator()(z);
384 T operator()(T z) const
386 return m_data.size() > 0 ? boost::math::tools::evaluate_polynomial(&m_data[0], z, m_data.size()) : T(0);
388 std::vector<T> chebyshev() const
390 return polynomial_to_chebyshev(m_data);
393 std::vector<T> const& data() const
398 std::vector<T> & data()
403 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
404 polynomial<T> prime() const
407 // Disable int->float conversion warning:
408 #pragma warning(push)
409 #pragma warning(disable:4244)
411 if (m_data.size() == 0)
413 return polynomial<T>({});
416 std::vector<T> p_data(m_data.size() - 1);
417 for (size_t i = 0; i < p_data.size(); ++i) {
418 p_data[i] = m_data[i+1]*static_cast<T>(i+1);
420 return polynomial<T>(std::move(p_data));
426 polynomial<T> integrate() const
428 std::vector<T> i_data(m_data.size() + 1);
429 // Choose integration constant such that P(0) = 0.
431 for (size_t i = 1; i < i_data.size(); ++i)
433 i_data[i] = m_data[i-1]/static_cast<T>(i);
435 return polynomial<T>(std::move(i_data));
439 polynomial& operator =(polynomial&& p) BOOST_NOEXCEPT
441 m_data = std::move(p.m_data);
445 polynomial& operator =(const polynomial& p)
452 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator +=(const U& value)
460 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator -=(const U& value)
468 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator *=(const U& value)
470 multiplication(value);
476 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator /=(const U& value)
484 typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial&>::type operator %=(const U& /*value*/)
486 // We can always divide by a scalar, so there is no remainder:
492 polynomial& operator +=(const polynomial<U>& value)
500 polynomial& operator -=(const polynomial<U>& value)
507 template <typename U, typename V>
508 void multiply(const polynomial<U>& a, const polynomial<V>& b) {
514 std::vector<T> prod(a.size() + b.size() - 1, T(0));
515 for (unsigned i = 0; i < a.size(); ++i)
516 for (unsigned j = 0; j < b.size(); ++j)
517 prod[i+j] += a.m_data[i] * b.m_data[j];
522 polynomial& operator *=(const polynomial<U>& value)
524 this->multiply(*this, value);
528 template <typename U>
529 polynomial& operator /=(const polynomial<U>& value)
531 *this = quotient_remainder(*this, value).first;
535 template <typename U>
536 polynomial& operator %=(const polynomial<U>& value)
538 *this = quotient_remainder(*this, value).second;
542 template <typename U>
543 polynomial& operator >>=(U const &n)
545 BOOST_ASSERT(n <= m_data.size());
546 m_data.erase(m_data.begin(), m_data.begin() + n);
550 template <typename U>
551 polynomial& operator <<=(U const &n)
553 m_data.insert(m_data.begin(), n, static_cast<T>(0));
558 // Convenient and efficient query for zero.
561 return m_data.empty();
564 // Conversion to bool.
565 #ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
566 typedef bool (polynomial::*unmentionable_type)() const;
568 BOOST_FORCEINLINE operator unmentionable_type() const
570 return is_zero() ? false : &polynomial::is_zero;
573 BOOST_FORCEINLINE explicit operator bool() const
575 return !m_data.empty();
579 // Fast way to set a polynomial to zero.
585 /** Remove zero coefficients 'from the top', that is for which there are no
586 * non-zero coefficients of higher degree. */
589 #ifndef BOOST_NO_CXX11_LAMBDAS
590 m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), [](const T& x)->bool { return x != T(0); }).base(), m_data.end());
592 using namespace boost::lambda;
593 m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), _1 != T(0)).base(), m_data.end());
598 template <class U, class R>
599 polynomial& addition(const U& value, R op)
601 if(m_data.size() == 0)
603 m_data[0] = op(m_data[0], value);
608 polynomial& addition(const U& value)
610 return addition(value, detail::plus());
614 polynomial& subtraction(const U& value)
616 return addition(value, detail::minus());
619 template <class U, class R>
620 polynomial& addition(const polynomial<U>& value, R op)
622 if (m_data.size() < value.size())
623 m_data.resize(value.size(), 0);
624 for(size_type i = 0; i < value.size(); ++i)
625 m_data[i] = op(m_data[i], value[i]);
630 polynomial& addition(const polynomial<U>& value)
632 return addition(value, detail::plus());
636 polynomial& subtraction(const polynomial<U>& value)
638 return addition(value, detail::minus());
642 polynomial& multiplication(const U& value)
644 #ifndef BOOST_NO_CXX11_LAMBDAS
645 std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x * value; });
647 using namespace boost::lambda;
648 std::transform(m_data.begin(), m_data.end(), m_data.begin(), ret<T>(_1 * value));
654 polynomial& division(const U& value)
656 #ifndef BOOST_NO_CXX11_LAMBDAS
657 std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x / value; });
659 using namespace boost::lambda;
660 std::transform(m_data.begin(), m_data.end(), m_data.begin(), ret<T>(_1 / value));
665 std::vector<T> m_data;
670 inline polynomial<T> operator + (const polynomial<T>& a, const polynomial<T>& b)
672 polynomial<T> result(a);
676 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
678 inline polynomial<T> operator + (polynomial<T>&& a, const polynomial<T>& b)
684 inline polynomial<T> operator + (const polynomial<T>& a, polynomial<T>&& b)
690 inline polynomial<T> operator + (polynomial<T>&& a, polynomial<T>&& b)
698 inline polynomial<T> operator - (const polynomial<T>& a, const polynomial<T>& b)
700 polynomial<T> result(a);
704 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
706 inline polynomial<T> operator - (polynomial<T>&& a, const polynomial<T>& b)
712 inline polynomial<T> operator - (const polynomial<T>& a, polynomial<T>&& b)
718 inline polynomial<T> operator - (polynomial<T>&& a, polynomial<T>&& b)
726 inline polynomial<T> operator * (const polynomial<T>& a, const polynomial<T>& b)
728 polynomial<T> result;
729 result.multiply(a, b);
734 inline polynomial<T> operator / (const polynomial<T>& a, const polynomial<T>& b)
736 return quotient_remainder(a, b).first;
740 inline polynomial<T> operator % (const polynomial<T>& a, const polynomial<T>& b)
742 return quotient_remainder(a, b).second;
745 template <class T, class U>
746 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator + (polynomial<T> a, const U& b)
752 template <class T, class U>
753 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator - (polynomial<T> a, const U& b)
759 template <class T, class U>
760 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator * (polynomial<T> a, const U& b)
766 template <class T, class U>
767 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator / (polynomial<T> a, const U& b)
773 template <class T, class U>
774 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator % (const polynomial<T>&, const U&)
776 // Since we can always divide by a scalar, result is always an empty polynomial:
777 return polynomial<T>();
780 template <class U, class T>
781 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator + (const U& a, polynomial<T> b)
787 template <class U, class T>
788 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator - (const U& a, polynomial<T> b)
794 template <class U, class T>
795 inline typename boost::enable_if_c<boost::is_constructible<T, U>::value, polynomial<T> >::type operator * (const U& a, polynomial<T> b)
802 bool operator == (const polynomial<T> &a, const polynomial<T> &b)
804 return a.data() == b.data();
808 bool operator != (const polynomial<T> &a, const polynomial<T> &b)
810 return a.data() != b.data();
813 template <typename T, typename U>
814 polynomial<T> operator >> (polynomial<T> a, const U& b)
820 template <typename T, typename U>
821 polynomial<T> operator << (polynomial<T> a, const U& b)
827 // Unary minus (negate).
829 polynomial<T> operator - (polynomial<T> a)
831 std::transform(a.data().begin(), a.data().end(), a.data().begin(), detail::negate());
836 bool odd(polynomial<T> const &a)
838 return a.size() > 0 && a[0] != static_cast<T>(0);
842 bool even(polynomial<T> const &a)
848 polynomial<T> pow(polynomial<T> base, int exp)
851 return policies::raise_domain_error(
852 "boost::math::tools::pow<%1%>",
853 "Negative powers are not supported for polynomials.",
854 base, policies::policy<>());
855 // if the policy is ignore_error or errno_on_error, raise_domain_error
856 // will return std::numeric_limits<polynomial<T>>::quiet_NaN(), which
857 // defaults to polynomial<T>(), which is the zero polynomial
858 polynomial<T> result(T(1));
861 /* "Exponentiation by squaring" */
871 template <class charT, class traits, class T>
872 inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& os, const polynomial<T>& poly)
875 for(unsigned i = 0; i < poly.size(); ++i)
889 // Polynomial specific overload of gcd algorithm:
891 #include <boost/math/tools/polynomial_gcd.hpp>
893 #endif // BOOST_MATH_TOOLS_POLYNOMIAL_HPP