File indexing completed on 2025-01-30 09:46:34
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef BOOST_MATH_TOOLS_POLYNOMIAL_HPP
0010 #define BOOST_MATH_TOOLS_POLYNOMIAL_HPP
0011
0012 #ifdef _MSC_VER
0013 #pragma once
0014 #endif
0015
0016 #include <boost/math/tools/assert.hpp>
0017 #include <boost/math/tools/config.hpp>
0018 #include <boost/math/tools/cxx03_warn.hpp>
0019 #include <boost/math/tools/rational.hpp>
0020 #include <boost/math/tools/real_cast.hpp>
0021 #include <boost/math/policies/error_handling.hpp>
0022 #include <boost/math/special_functions/binomial.hpp>
0023 #include <boost/math/tools/detail/is_const_iterable.hpp>
0024
0025 #include <vector>
0026 #include <ostream>
0027 #include <algorithm>
0028 #include <initializer_list>
0029 #include <type_traits>
0030 #include <iterator>
0031
0032 namespace boost{ namespace math{ namespace tools{
0033
0034 template <class T>
0035 T chebyshev_coefficient(unsigned n, unsigned m)
0036 {
0037 BOOST_MATH_STD_USING
0038 if(m > n)
0039 return 0;
0040 if((n & 1) != (m & 1))
0041 return 0;
0042 if(n == 0)
0043 return 1;
0044 T result = T(n) / 2;
0045 unsigned r = n - m;
0046 r /= 2;
0047
0048 BOOST_MATH_ASSERT(n - 2 * r == m);
0049
0050 if(r & 1)
0051 result = -result;
0052 result /= n - r;
0053 result *= boost::math::binomial_coefficient<T>(n - r, r);
0054 result *= ldexp(1.0f, m);
0055 return result;
0056 }
0057
0058 template <class Seq>
0059 Seq polynomial_to_chebyshev(const Seq& s)
0060 {
0061
0062 typedef typename Seq::value_type value_type;
0063 typedef typename Seq::difference_type difference_type;
0064 Seq result(s);
0065 difference_type order = s.size() - 1;
0066 difference_type even_order = order & 1 ? order - 1 : order;
0067 difference_type odd_order = order & 1 ? order : order - 1;
0068
0069 for(difference_type i = even_order; i >= 0; i -= 2)
0070 {
0071 value_type val = s[i];
0072 for(difference_type k = even_order; k > i; k -= 2)
0073 {
0074 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
0075 }
0076 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
0077 result[i] = val;
0078 }
0079 result[0] *= 2;
0080
0081 for(difference_type i = odd_order; i >= 0; i -= 2)
0082 {
0083 value_type val = s[i];
0084 for(difference_type k = odd_order; k > i; k -= 2)
0085 {
0086 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
0087 }
0088 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
0089 result[i] = val;
0090 }
0091 return result;
0092 }
0093
0094 template <class Seq, class T>
0095 T evaluate_chebyshev(const Seq& a, const T& x)
0096 {
0097
0098 typedef typename Seq::difference_type difference_type;
0099 T yk2 = 0;
0100 T yk1 = 0;
0101 T yk = 0;
0102 for(difference_type i = a.size() - 1; i >= 1; --i)
0103 {
0104 yk2 = yk1;
0105 yk1 = yk;
0106 yk = 2 * x * yk1 - yk2 + a[i];
0107 }
0108 return a[0] / 2 + yk * x - yk1;
0109 }
0110
0111
0112 template <typename T>
0113 class polynomial;
0114
0115 namespace detail {
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126 template <typename T, typename N>
0127 typename std::enable_if<!std::numeric_limits<T>::is_integer, void >::type
0128 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
0129 {
0130 q[k] = u[n + k] / v[n];
0131 for (N j = n + k; j > k;)
0132 {
0133 j--;
0134 u[j] -= q[k] * v[j - k];
0135 }
0136 }
0137
0138 template <class T, class N>
0139 T integer_power(T t, N n)
0140 {
0141 switch(n)
0142 {
0143 case 0:
0144 return static_cast<T>(1u);
0145 case 1:
0146 return t;
0147 case 2:
0148 return t * t;
0149 case 3:
0150 return t * t * t;
0151 }
0152 T result = integer_power(t, n / 2);
0153 result *= result;
0154 if(n & 1)
0155 result *= t;
0156 return result;
0157 }
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169 template <typename T, typename N>
0170 typename std::enable_if<std::numeric_limits<T>::is_integer, void >::type
0171 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
0172 {
0173 q[k] = u[n + k] * integer_power(v[n], k);
0174 for (N j = n + k; j > 0;)
0175 {
0176 j--;
0177 u[j] = v[n] * u[j] - (j < k ? T(0) : u[n + k] * v[j - k]);
0178 }
0179 }
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189 template <typename T>
0190 std::pair< polynomial<T>, polynomial<T> >
0191 division(polynomial<T> u, const polynomial<T>& v)
0192 {
0193 BOOST_MATH_ASSERT(v.size() <= u.size());
0194 BOOST_MATH_ASSERT(v);
0195 BOOST_MATH_ASSERT(u);
0196
0197 typedef typename polynomial<T>::size_type N;
0198
0199 N const m = u.size() - 1, n = v.size() - 1;
0200 N k = m - n;
0201 polynomial<T> q;
0202 q.data().resize(m - n + 1);
0203
0204 do
0205 {
0206 division_impl(q, u, v, n, k);
0207 }
0208 while (k-- != 0);
0209 u.data().resize(n);
0210 u.normalize();
0211 return std::make_pair(q, u);
0212 }
0213
0214
0215
0216
0217
0218 struct negate
0219 {
0220 template <class T>
0221 T operator()(T const &x) const
0222 {
0223 return -x;
0224 }
0225 };
0226
0227 struct plus
0228 {
0229 template <class T, class U>
0230 T operator()(T const &x, U const& y) const
0231 {
0232 return x + y;
0233 }
0234 };
0235
0236 struct minus
0237 {
0238 template <class T, class U>
0239 T operator()(T const &x, U const& y) const
0240 {
0241 return x - y;
0242 }
0243 };
0244
0245 }
0246
0247
0248
0249
0250 template <class T>
0251 polynomial<T> zero_element(std::multiplies< polynomial<T> >)
0252 {
0253 return polynomial<T>();
0254 }
0255
0256 template <class T>
0257 polynomial<T> identity_element(std::multiplies< polynomial<T> >)
0258 {
0259 return polynomial<T>(T(1));
0260 }
0261
0262
0263
0264
0265
0266 template <typename T>
0267 std::pair< polynomial<T>, polynomial<T> >
0268 quotient_remainder(const polynomial<T>& dividend, const polynomial<T>& divisor)
0269 {
0270 BOOST_MATH_ASSERT(divisor);
0271 if (dividend.size() < divisor.size())
0272 return std::make_pair(polynomial<T>(), dividend);
0273 return detail::division(dividend, divisor);
0274 }
0275
0276
0277 template <class T>
0278 class polynomial
0279 {
0280 public:
0281
0282 typedef typename std::vector<T>::value_type value_type;
0283 typedef typename std::vector<T>::size_type size_type;
0284
0285
0286 polynomial()= default;
0287
0288 template <class U>
0289 polynomial(const U* data, unsigned order)
0290 : m_data(data, data + order + 1)
0291 {
0292 normalize();
0293 }
0294
0295 template <class I>
0296 polynomial(I first, I last)
0297 : m_data(first, last)
0298 {
0299 normalize();
0300 }
0301
0302 template <class I>
0303 polynomial(I first, unsigned length)
0304 : m_data(first, std::next(first, length + 1))
0305 {
0306 normalize();
0307 }
0308
0309 polynomial(std::vector<T>&& p) : m_data(std::move(p))
0310 {
0311 normalize();
0312 }
0313
0314 template <class U, typename std::enable_if<std::is_convertible<U, T>::value, bool>::type = true>
0315 explicit polynomial(const U& point)
0316 {
0317 if (point != U(0))
0318 m_data.push_back(point);
0319 }
0320
0321
0322 polynomial(polynomial&& p) noexcept
0323 : m_data(std::move(p.m_data)) { }
0324
0325
0326 polynomial(const polynomial& p)
0327 : m_data(p.m_data) { }
0328
0329 template <class U>
0330 polynomial(const polynomial<U>& p)
0331 {
0332 m_data.resize(p.size());
0333 for(unsigned i = 0; i < p.size(); ++i)
0334 {
0335 m_data[i] = boost::math::tools::real_cast<T>(p[i]);
0336 }
0337 }
0338 #ifdef BOOST_MATH_HAS_IS_CONST_ITERABLE
0339 template <class Range, typename std::enable_if<boost::math::tools::detail::is_const_iterable<Range>::value, bool>::type = true>
0340 explicit polynomial(const Range& r)
0341 : polynomial(r.begin(), r.end())
0342 {
0343 }
0344 #endif
0345 polynomial(std::initializer_list<T> l) : polynomial(std::begin(l), std::end(l))
0346 {
0347 }
0348
0349 polynomial&
0350 operator=(std::initializer_list<T> l)
0351 {
0352 m_data.assign(std::begin(l), std::end(l));
0353 normalize();
0354 return *this;
0355 }
0356
0357
0358
0359 size_type size() const { return m_data.size(); }
0360 size_type degree() const
0361 {
0362 if (size() == 0)
0363 BOOST_MATH_THROW_EXCEPTION(std::logic_error("degree() is undefined for the zero polynomial."));
0364 return m_data.size() - 1;
0365 }
0366 value_type& operator[](size_type i)
0367 {
0368 return m_data[i];
0369 }
0370 const value_type& operator[](size_type i) const
0371 {
0372 return m_data[i];
0373 }
0374
0375 T evaluate(T z) const
0376 {
0377 return this->operator()(z);
0378 }
0379
0380 T operator()(T z) const
0381 {
0382 return m_data.size() > 0 ? boost::math::tools::evaluate_polynomial((m_data).data(), z, m_data.size()) : T(0);
0383 }
0384 std::vector<T> chebyshev() const
0385 {
0386 return polynomial_to_chebyshev(m_data);
0387 }
0388
0389 std::vector<T> const& data() const
0390 {
0391 return m_data;
0392 }
0393
0394 std::vector<T> & data()
0395 {
0396 return m_data;
0397 }
0398
0399 polynomial<T> prime() const
0400 {
0401 #ifdef _MSC_VER
0402
0403 #pragma warning(push)
0404 #pragma warning(disable:4244)
0405 #endif
0406 if (m_data.size() == 0)
0407 {
0408 return polynomial<T>({});
0409 }
0410
0411 std::vector<T> p_data(m_data.size() - 1);
0412 for (size_t i = 0; i < p_data.size(); ++i) {
0413 p_data[i] = m_data[i+1]*static_cast<T>(i+1);
0414 }
0415 return polynomial<T>(std::move(p_data));
0416 #ifdef _MSC_VER
0417 #pragma warning(pop)
0418 #endif
0419 }
0420
0421 polynomial<T> integrate() const
0422 {
0423 std::vector<T> i_data(m_data.size() + 1);
0424
0425 i_data[0] = T(0);
0426 for (size_t i = 1; i < i_data.size(); ++i)
0427 {
0428 i_data[i] = m_data[i-1]/static_cast<T>(i);
0429 }
0430 return polynomial<T>(std::move(i_data));
0431 }
0432
0433
0434 polynomial& operator =(polynomial&& p) noexcept
0435 {
0436 m_data = std::move(p.m_data);
0437 return *this;
0438 }
0439
0440 polynomial& operator =(const polynomial& p)
0441 {
0442 m_data = p.m_data;
0443 return *this;
0444 }
0445
0446 template <class U>
0447 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator +=(const U& value)
0448 {
0449 addition(value);
0450 normalize();
0451 return *this;
0452 }
0453
0454 template <class U>
0455 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator -=(const U& value)
0456 {
0457 subtraction(value);
0458 normalize();
0459 return *this;
0460 }
0461
0462 template <class U>
0463 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator *=(const U& value)
0464 {
0465 multiplication(value);
0466 normalize();
0467 return *this;
0468 }
0469
0470 template <class U>
0471 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator /=(const U& value)
0472 {
0473 division(value);
0474 normalize();
0475 return *this;
0476 }
0477
0478 template <class U>
0479 typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator %=(const U& )
0480 {
0481
0482 this->set_zero();
0483 return *this;
0484 }
0485
0486 template <class U>
0487 polynomial& operator +=(const polynomial<U>& value)
0488 {
0489 addition(value);
0490 normalize();
0491 return *this;
0492 }
0493
0494 template <class U>
0495 polynomial& operator -=(const polynomial<U>& value)
0496 {
0497 subtraction(value);
0498 normalize();
0499 return *this;
0500 }
0501
0502 template <typename U, typename V>
0503 void multiply(const polynomial<U>& a, const polynomial<V>& b) {
0504 if (!a || !b)
0505 {
0506 this->set_zero();
0507 return;
0508 }
0509 std::vector<T> prod(a.size() + b.size() - 1, T(0));
0510 for (unsigned i = 0; i < a.size(); ++i)
0511 for (unsigned j = 0; j < b.size(); ++j)
0512 prod[i+j] += a.m_data[i] * b.m_data[j];
0513 m_data.swap(prod);
0514 }
0515
0516 template <class U>
0517 polynomial& operator *=(const polynomial<U>& value)
0518 {
0519 this->multiply(*this, value);
0520 return *this;
0521 }
0522
0523 template <typename U>
0524 polynomial& operator /=(const polynomial<U>& value)
0525 {
0526 *this = quotient_remainder(*this, value).first;
0527 return *this;
0528 }
0529
0530 template <typename U>
0531 polynomial& operator %=(const polynomial<U>& value)
0532 {
0533 *this = quotient_remainder(*this, value).second;
0534 return *this;
0535 }
0536
0537 template <typename U>
0538 polynomial& operator >>=(U const &n)
0539 {
0540 BOOST_MATH_ASSERT(n <= m_data.size());
0541 m_data.erase(m_data.begin(), m_data.begin() + n);
0542 return *this;
0543 }
0544
0545 template <typename U>
0546 polynomial& operator <<=(U const &n)
0547 {
0548 m_data.insert(m_data.begin(), n, static_cast<T>(0));
0549 normalize();
0550 return *this;
0551 }
0552
0553
0554 bool is_zero() const
0555 {
0556 return m_data.empty();
0557 }
0558
0559
0560 inline explicit operator bool() const
0561 {
0562 return !m_data.empty();
0563 }
0564
0565
0566 void set_zero()
0567 {
0568 m_data.clear();
0569 }
0570
0571
0572
0573 void normalize()
0574 {
0575 m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), [](const T& x)->bool { return x != T(0); }).base(), m_data.end());
0576 }
0577
0578 private:
0579 template <class U, class R>
0580 polynomial& addition(const U& value, R op)
0581 {
0582 if(m_data.size() == 0)
0583 m_data.resize(1, 0);
0584 m_data[0] = op(m_data[0], value);
0585 return *this;
0586 }
0587
0588 template <class U>
0589 polynomial& addition(const U& value)
0590 {
0591 return addition(value, detail::plus());
0592 }
0593
0594 template <class U>
0595 polynomial& subtraction(const U& value)
0596 {
0597 return addition(value, detail::minus());
0598 }
0599
0600 template <class U, class R>
0601 polynomial& addition(const polynomial<U>& value, R op)
0602 {
0603 if (m_data.size() < value.size())
0604 m_data.resize(value.size(), 0);
0605 for(size_type i = 0; i < value.size(); ++i)
0606 m_data[i] = op(m_data[i], value[i]);
0607 return *this;
0608 }
0609
0610 template <class U>
0611 polynomial& addition(const polynomial<U>& value)
0612 {
0613 return addition(value, detail::plus());
0614 }
0615
0616 template <class U>
0617 polynomial& subtraction(const polynomial<U>& value)
0618 {
0619 return addition(value, detail::minus());
0620 }
0621
0622 template <class U>
0623 polynomial& multiplication(const U& value)
0624 {
0625 std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x * value; });
0626 return *this;
0627 }
0628
0629 template <class U>
0630 polynomial& division(const U& value)
0631 {
0632 std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x / value; });
0633 return *this;
0634 }
0635
0636 std::vector<T> m_data;
0637 };
0638
0639
0640 template <class T>
0641 inline polynomial<T> operator + (const polynomial<T>& a, const polynomial<T>& b)
0642 {
0643 polynomial<T> result(a);
0644 result += b;
0645 return result;
0646 }
0647
0648 template <class T>
0649 inline polynomial<T> operator + (polynomial<T>&& a, const polynomial<T>& b)
0650 {
0651 a += b;
0652 return std::move(a);
0653 }
0654 template <class T>
0655 inline polynomial<T> operator + (const polynomial<T>& a, polynomial<T>&& b)
0656 {
0657 b += a;
0658 return b;
0659 }
0660 template <class T>
0661 inline polynomial<T> operator + (polynomial<T>&& a, polynomial<T>&& b)
0662 {
0663 a += b;
0664 return a;
0665 }
0666
0667 template <class T>
0668 inline polynomial<T> operator - (const polynomial<T>& a, const polynomial<T>& b)
0669 {
0670 polynomial<T> result(a);
0671 result -= b;
0672 return result;
0673 }
0674
0675 template <class T>
0676 inline polynomial<T> operator - (polynomial<T>&& a, const polynomial<T>& b)
0677 {
0678 a -= b;
0679 return a;
0680 }
0681 template <class T>
0682 inline polynomial<T> operator - (const polynomial<T>& a, polynomial<T>&& b)
0683 {
0684 b -= a;
0685 return -b;
0686 }
0687 template <class T>
0688 inline polynomial<T> operator - (polynomial<T>&& a, polynomial<T>&& b)
0689 {
0690 a -= b;
0691 return a;
0692 }
0693
0694 template <class T>
0695 inline polynomial<T> operator * (const polynomial<T>& a, const polynomial<T>& b)
0696 {
0697 polynomial<T> result;
0698 result.multiply(a, b);
0699 return result;
0700 }
0701
0702 template <class T>
0703 inline polynomial<T> operator / (const polynomial<T>& a, const polynomial<T>& b)
0704 {
0705 return quotient_remainder(a, b).first;
0706 }
0707
0708 template <class T>
0709 inline polynomial<T> operator % (const polynomial<T>& a, const polynomial<T>& b)
0710 {
0711 return quotient_remainder(a, b).second;
0712 }
0713
0714 template <class T, class U>
0715 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator + (polynomial<T> a, const U& b)
0716 {
0717 a += b;
0718 return a;
0719 }
0720
0721 template <class T, class U>
0722 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator - (polynomial<T> a, const U& b)
0723 {
0724 a -= b;
0725 return a;
0726 }
0727
0728 template <class T, class U>
0729 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator * (polynomial<T> a, const U& b)
0730 {
0731 a *= b;
0732 return a;
0733 }
0734
0735 template <class T, class U>
0736 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator / (polynomial<T> a, const U& b)
0737 {
0738 a /= b;
0739 return a;
0740 }
0741
0742 template <class T, class U>
0743 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator % (const polynomial<T>&, const U&)
0744 {
0745
0746 return polynomial<T>();
0747 }
0748
0749 template <class U, class T>
0750 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator + (const U& a, polynomial<T> b)
0751 {
0752 b += a;
0753 return b;
0754 }
0755
0756 template <class U, class T>
0757 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator - (const U& a, polynomial<T> b)
0758 {
0759 b -= a;
0760 return -b;
0761 }
0762
0763 template <class U, class T>
0764 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator * (const U& a, polynomial<T> b)
0765 {
0766 b *= a;
0767 return b;
0768 }
0769
0770 template <class T>
0771 bool operator == (const polynomial<T> &a, const polynomial<T> &b)
0772 {
0773 return a.data() == b.data();
0774 }
0775
0776 template <class T>
0777 bool operator != (const polynomial<T> &a, const polynomial<T> &b)
0778 {
0779 return a.data() != b.data();
0780 }
0781
0782 template <typename T, typename U>
0783 polynomial<T> operator >> (polynomial<T> a, const U& b)
0784 {
0785 a >>= b;
0786 return a;
0787 }
0788
0789 template <typename T, typename U>
0790 polynomial<T> operator << (polynomial<T> a, const U& b)
0791 {
0792 a <<= b;
0793 return a;
0794 }
0795
0796
0797 template <class T>
0798 polynomial<T> operator - (polynomial<T> a)
0799 {
0800 std::transform(a.data().begin(), a.data().end(), a.data().begin(), detail::negate());
0801 return a;
0802 }
0803
0804 template <class T>
0805 bool odd(polynomial<T> const &a)
0806 {
0807 return a.size() > 0 && a[0] != static_cast<T>(0);
0808 }
0809
0810 template <class T>
0811 bool even(polynomial<T> const &a)
0812 {
0813 return !odd(a);
0814 }
0815
0816 template <class T>
0817 polynomial<T> pow(polynomial<T> base, int exp)
0818 {
0819 if (exp < 0)
0820 return policies::raise_domain_error(
0821 "boost::math::tools::pow<%1%>",
0822 "Negative powers are not supported for polynomials.",
0823 base, policies::policy<>());
0824
0825
0826
0827 polynomial<T> result(T(1));
0828 if (exp & 1)
0829 result = base;
0830
0831 while (exp >>= 1)
0832 {
0833 base *= base;
0834 if (exp & 1)
0835 result *= base;
0836 }
0837 return result;
0838 }
0839
0840 template <class charT, class traits, class T>
0841 inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& os, const polynomial<T>& poly)
0842 {
0843 os << "{ ";
0844 for(unsigned i = 0; i < poly.size(); ++i)
0845 {
0846 if(i) os << ", ";
0847 os << poly[i];
0848 }
0849 os << " }";
0850 return os;
0851 }
0852
0853 }
0854 }
0855 }
0856
0857
0858
0859
0860 #include <boost/math/tools/polynomial_gcd.hpp>
0861
0862 #endif