polynomial.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. // (C) Copyright John Maddock 2006.
  2. // (C) Copyright Jeremy William Murphy 2015.
  3. // Use, modification and distribution are subject to the
  4. // Boost Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_MATH_TOOLS_POLYNOMIAL_HPP
  7. #define BOOST_MATH_TOOLS_POLYNOMIAL_HPP
  8. #ifdef _MSC_VER
  9. #pragma once
  10. #endif
  11. #include <boost/assert.hpp>
  12. #include <boost/config.hpp>
  13. #include <boost/function.hpp>
  14. #include <boost/lambda/lambda.hpp>
  15. #include <boost/math/tools/rational.hpp>
  16. #include <boost/math/tools/real_cast.hpp>
  17. #include <boost/math/special_functions/binomial.hpp>
  18. #include <boost/operators.hpp>
  19. #include <vector>
  20. #include <ostream>
  21. #include <algorithm>
  22. #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
  23. #include <initializer_list>
  24. #endif
  25. namespace boost{ namespace math{ namespace tools{
  26. template <class T>
  27. T chebyshev_coefficient(unsigned n, unsigned m)
  28. {
  29. BOOST_MATH_STD_USING
  30. if(m > n)
  31. return 0;
  32. if((n & 1) != (m & 1))
  33. return 0;
  34. if(n == 0)
  35. return 1;
  36. T result = T(n) / 2;
  37. unsigned r = n - m;
  38. r /= 2;
  39. BOOST_ASSERT(n - 2 * r == m);
  40. if(r & 1)
  41. result = -result;
  42. result /= n - r;
  43. result *= boost::math::binomial_coefficient<T>(n - r, r);
  44. result *= ldexp(1.0f, m);
  45. return result;
  46. }
  47. template <class Seq>
  48. Seq polynomial_to_chebyshev(const Seq& s)
  49. {
  50. // Converts a Polynomial into Chebyshev form:
  51. typedef typename Seq::value_type value_type;
  52. typedef typename Seq::difference_type difference_type;
  53. Seq result(s);
  54. difference_type order = s.size() - 1;
  55. difference_type even_order = order & 1 ? order - 1 : order;
  56. difference_type odd_order = order & 1 ? order : order - 1;
  57. for(difference_type i = even_order; i >= 0; i -= 2)
  58. {
  59. value_type val = s[i];
  60. for(difference_type k = even_order; k > i; k -= 2)
  61. {
  62. val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
  63. }
  64. val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
  65. result[i] = val;
  66. }
  67. result[0] *= 2;
  68. for(difference_type i = odd_order; i >= 0; i -= 2)
  69. {
  70. value_type val = s[i];
  71. for(difference_type k = odd_order; k > i; k -= 2)
  72. {
  73. val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
  74. }
  75. val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
  76. result[i] = val;
  77. }
  78. return result;
  79. }
  80. template <class Seq, class T>
  81. T evaluate_chebyshev(const Seq& a, const T& x)
  82. {
  83. // Clenshaw's formula:
  84. typedef typename Seq::difference_type difference_type;
  85. T yk2 = 0;
  86. T yk1 = 0;
  87. T yk = 0;
  88. for(difference_type i = a.size() - 1; i >= 1; --i)
  89. {
  90. yk2 = yk1;
  91. yk1 = yk;
  92. yk = 2 * x * yk1 - yk2 + a[i];
  93. }
  94. return a[0] / 2 + yk * x - yk1;
  95. }
  96. template <typename T>
  97. class polynomial;
  98. namespace detail {
  99. /**
  100. * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
  101. * Chapter 4.6.1, Algorithm D: Division of polynomials over a field.
  102. *
  103. * @tparam T Coefficient type, must be not be an integer.
  104. *
  105. * Template-parameter T actually must be a field but we don't currently have that
  106. * subtlety of distinction.
  107. */
  108. template <typename T, typename N>
  109. BOOST_DEDUCED_TYPENAME disable_if_c<std::numeric_limits<T>::is_integer, void >::type
  110. division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
  111. {
  112. q[k] = u[n + k] / v[n];
  113. for (N j = n + k; j > k;)
  114. {
  115. j--;
  116. u[j] -= q[k] * v[j - k];
  117. }
  118. }
  119. template <class T, class N>
  120. T integer_power(T t, N n)
  121. {
  122. switch(n)
  123. {
  124. case 0:
  125. return static_cast<T>(1u);
  126. case 1:
  127. return t;
  128. case 2:
  129. return t * t;
  130. case 3:
  131. return t * t * t;
  132. }
  133. T result = integer_power(t, n / 2);
  134. result *= result;
  135. if(n & 1)
  136. result *= t;
  137. return result;
  138. }
  139. /**
  140. * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
  141. * Chapter 4.6.1, Algorithm R: Pseudo-division of polynomials.
  142. *
  143. * @tparam T Coefficient type, must be an integer.
  144. *
  145. * Template-parameter T actually must be a unique factorization domain but we
  146. * don't currently have that subtlety of distinction.
  147. */
  148. template <typename T, typename N>
  149. BOOST_DEDUCED_TYPENAME enable_if_c<std::numeric_limits<T>::is_integer, void >::type
  150. division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
  151. {
  152. q[k] = u[n + k] * integer_power(v[n], k);
  153. for (N j = n + k; j > 0;)
  154. {
  155. j--;
  156. u[j] = v[n] * u[j] - (j < k ? T(0) : u[n + k] * v[j - k]);
  157. }
  158. }
  159. /**
  160. * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
  161. * Chapter 4.6.1, Algorithm D and R: Main loop.
  162. *
  163. * @param u Dividend.
  164. * @param v Divisor.
  165. */
  166. template <typename T>
  167. std::pair< polynomial<T>, polynomial<T> >
  168. division(polynomial<T> u, const polynomial<T>& v)
  169. {
  170. BOOST_ASSERT(v.size() <= u.size());
  171. BOOST_ASSERT(v != zero_element(std::multiplies< polynomial<T> >()));
  172. BOOST_ASSERT(u != zero_element(std::multiplies< polynomial<T> >()));
  173. typedef typename polynomial<T>::size_type N;
  174. N const m = u.size() - 1, n = v.size() - 1;
  175. N k = m - n;
  176. polynomial<T> q;
  177. q.data().resize(m - n + 1);
  178. do
  179. {
  180. division_impl(q, u, v, n, k);
  181. }
  182. while (k-- != 0);
  183. u.data().resize(n);
  184. u.normalize(); // Occasionally, the remainder is zeroes.
  185. return std::make_pair(q, u);
  186. }
  187. template <class T>
  188. struct identity
  189. {
  190. T operator()(T const &x) const
  191. {
  192. return x;
  193. }
  194. };
  195. } // namespace detail
  196. /**
  197. * Returns the zero element for multiplication of polynomials.
  198. */
  199. template <class T>
  200. polynomial<T> zero_element(std::multiplies< polynomial<T> >)
  201. {
  202. return polynomial<T>();
  203. }
  204. template <class T>
  205. polynomial<T> identity_element(std::multiplies< polynomial<T> >)
  206. {
  207. return polynomial<T>(T(1));
  208. }
  209. /* Calculates a / b and a % b, returning the pair (quotient, remainder) together
  210. * because the same amount of computation yields both.
  211. * This function is not defined for division by zero: user beware.
  212. */
  213. template <typename T>
  214. std::pair< polynomial<T>, polynomial<T> >
  215. quotient_remainder(const polynomial<T>& dividend, const polynomial<T>& divisor)
  216. {
  217. BOOST_ASSERT(divisor != zero_element(std::multiplies< polynomial<T> >()));
  218. if (dividend.size() < divisor.size())
  219. return std::make_pair(zero_element(std::multiplies< polynomial<T> >()), dividend);
  220. return detail::division(dividend, divisor);
  221. }
  222. template <class T>
  223. class polynomial :
  224. equality_comparable< polynomial<T>,
  225. dividable< polynomial<T>,
  226. dividable2< polynomial<T>, T,
  227. modable< polynomial<T>,
  228. modable2< polynomial<T>, T > > > > >
  229. {
  230. public:
  231. // typedefs:
  232. typedef typename std::vector<T>::value_type value_type;
  233. typedef typename std::vector<T>::size_type size_type;
  234. // construct:
  235. polynomial(){}
  236. template <class U>
  237. polynomial(const U* data, unsigned order)
  238. : m_data(data, data + order + 1)
  239. {
  240. normalize();
  241. }
  242. template <class I>
  243. polynomial(I first, I last)
  244. : m_data(first, last)
  245. {
  246. normalize();
  247. }
  248. template <class U>
  249. explicit polynomial(const U& point)
  250. {
  251. if (point != U(0))
  252. m_data.push_back(point);
  253. }
  254. // copy:
  255. polynomial(const polynomial& p)
  256. : m_data(p.m_data) { }
  257. template <class U>
  258. polynomial(const polynomial<U>& p)
  259. {
  260. for(unsigned i = 0; i < p.size(); ++i)
  261. {
  262. m_data.push_back(boost::math::tools::real_cast<T>(p[i]));
  263. }
  264. }
  265. #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
  266. polynomial(std::initializer_list<T> l) : polynomial(std::begin(l), std::end(l))
  267. {
  268. }
  269. polynomial&
  270. operator=(std::initializer_list<T> l)
  271. {
  272. m_data.assign(std::begin(l), std::end(l));
  273. return *this;
  274. }
  275. #endif
  276. // access:
  277. size_type size()const { return m_data.size(); }
  278. size_type degree()const
  279. {
  280. if (size() == 0)
  281. throw std::logic_error("degree() is undefined for the zero polynomial.");
  282. return m_data.size() - 1;
  283. }
  284. value_type& operator[](size_type i)
  285. {
  286. return m_data[i];
  287. }
  288. const value_type& operator[](size_type i)const
  289. {
  290. return m_data[i];
  291. }
  292. T evaluate(T z)const
  293. {
  294. return boost::math::tools::evaluate_polynomial(&m_data[0], z, m_data.size());;
  295. }
  296. std::vector<T> chebyshev()const
  297. {
  298. return polynomial_to_chebyshev(m_data);
  299. }
  300. std::vector<T> const& data() const
  301. {
  302. return m_data;
  303. }
  304. std::vector<T> & data()
  305. {
  306. return m_data;
  307. }
  308. // operators:
  309. template <class U>
  310. polynomial& operator +=(const U& value)
  311. {
  312. addition(value);
  313. normalize();
  314. return *this;
  315. }
  316. template <class U>
  317. polynomial& operator -=(const U& value)
  318. {
  319. subtraction(value);
  320. normalize();
  321. return *this;
  322. }
  323. template <class U>
  324. polynomial& operator *=(const U& value)
  325. {
  326. multiplication(value);
  327. normalize();
  328. return *this;
  329. }
  330. template <class U>
  331. polynomial& operator /=(const U& value)
  332. {
  333. division(value);
  334. normalize();
  335. return *this;
  336. }
  337. template <class U>
  338. polynomial& operator %=(const U& /*value*/)
  339. {
  340. // We can always divide by a scalar, so there is no remainder:
  341. *this = zero_element(std::multiplies<polynomial>());
  342. return *this;
  343. }
  344. template <class U>
  345. polynomial& operator +=(const polynomial<U>& value)
  346. {
  347. addition(value);
  348. normalize();
  349. return *this;
  350. }
  351. template <class U>
  352. polynomial& operator -=(const polynomial<U>& value)
  353. {
  354. subtraction(value);
  355. normalize();
  356. return *this;
  357. }
  358. template <class U>
  359. polynomial& operator *=(const polynomial<U>& value)
  360. {
  361. // TODO: FIXME: use O(N log(N)) algorithm!!!
  362. polynomial const zero = zero_element(std::multiplies<polynomial>());
  363. if (value == zero)
  364. {
  365. *this = zero;
  366. return *this;
  367. }
  368. polynomial base(*this);
  369. this->multiplication(value[0]);
  370. for(size_type i = 1; i < value.size(); ++i)
  371. {
  372. polynomial t(base);
  373. t.multiplication(value[i]);
  374. size_type s = size() - i;
  375. for(size_type j = 0; j < s; ++j)
  376. {
  377. m_data[i+j] += t[j];
  378. }
  379. for(size_type j = s; j < t.size(); ++j)
  380. m_data.push_back(t[j]);
  381. }
  382. return *this;
  383. }
  384. template <typename U>
  385. polynomial& operator /=(const polynomial<U>& value)
  386. {
  387. *this = quotient_remainder(*this, value).first;
  388. return *this;
  389. }
  390. template <typename U>
  391. polynomial& operator %=(const polynomial<U>& value)
  392. {
  393. *this = quotient_remainder(*this, value).second;
  394. return *this;
  395. }
  396. /** Remove zero coefficients 'from the top', that is for which there are no
  397. * non-zero coefficients of higher degree. */
  398. void normalize()
  399. {
  400. using namespace boost::lambda;
  401. m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), _1 != T(0)).base(), m_data.end());
  402. }
  403. private:
  404. template <class U, class R1, class R2>
  405. polynomial& addition(const U& value, R1 sign, R2 op)
  406. {
  407. if(m_data.size() == 0)
  408. m_data.push_back(sign(value));
  409. else
  410. m_data[0] = op(m_data[0], value);
  411. return *this;
  412. }
  413. template <class U>
  414. polynomial& addition(const U& value)
  415. {
  416. return addition(value, detail::identity<U>(), std::plus<U>());
  417. }
  418. template <class U>
  419. polynomial& subtraction(const U& value)
  420. {
  421. return addition(value, std::negate<U>(), std::minus<U>());
  422. }
  423. template <class U, class R1, class R2>
  424. polynomial& addition(const polynomial<U>& value, R1 sign, R2 op)
  425. {
  426. size_type s1 = (std::min)(m_data.size(), value.size());
  427. for(size_type i = 0; i < s1; ++i)
  428. m_data[i] = op(m_data[i], value[i]);
  429. for(size_type i = s1; i < value.size(); ++i)
  430. m_data.push_back(sign(value[i]));
  431. return *this;
  432. }
  433. template <class U>
  434. polynomial& addition(const polynomial<U>& value)
  435. {
  436. return addition(value, detail::identity<U>(), std::plus<U>());
  437. }
  438. template <class U>
  439. polynomial& subtraction(const polynomial<U>& value)
  440. {
  441. return addition(value, std::negate<U>(), std::minus<U>());
  442. }
  443. template <class U>
  444. polynomial& multiplication(const U& value)
  445. {
  446. using namespace boost::lambda;
  447. std::transform(m_data.begin(), m_data.end(), m_data.begin(), ret<T>(_1 * value));
  448. return *this;
  449. }
  450. template <class U>
  451. polynomial& division(const U& value)
  452. {
  453. using namespace boost::lambda;
  454. std::transform(m_data.begin(), m_data.end(), m_data.begin(), ret<T>(_1 / value));
  455. return *this;
  456. }
  457. std::vector<T> m_data;
  458. };
  459. template <class T>
  460. inline polynomial<T> operator + (const polynomial<T>& a, const polynomial<T>& b)
  461. {
  462. polynomial<T> result(a);
  463. result += b;
  464. return result;
  465. }
  466. template <class T>
  467. inline polynomial<T> operator - (const polynomial<T>& a, const polynomial<T>& b)
  468. {
  469. polynomial<T> result(a);
  470. result -= b;
  471. return result;
  472. }
  473. template <class T>
  474. inline polynomial<T> operator * (const polynomial<T>& a, const polynomial<T>& b)
  475. {
  476. polynomial<T> result(a);
  477. result *= b;
  478. return result;
  479. }
  480. template <class T, class U>
  481. inline polynomial<T> operator + (const polynomial<T>& a, const U& b)
  482. {
  483. polynomial<T> result(a);
  484. result += b;
  485. return result;
  486. }
  487. template <class T, class U>
  488. inline polynomial<T> operator - (const polynomial<T>& a, const U& b)
  489. {
  490. polynomial<T> result(a);
  491. result -= b;
  492. return result;
  493. }
  494. template <class T, class U>
  495. inline polynomial<T> operator * (const polynomial<T>& a, const U& b)
  496. {
  497. polynomial<T> result(a);
  498. result *= b;
  499. return result;
  500. }
  501. template <class U, class T>
  502. inline polynomial<T> operator + (const U& a, const polynomial<T>& b)
  503. {
  504. polynomial<T> result(b);
  505. result += a;
  506. return result;
  507. }
  508. template <class U, class T>
  509. inline polynomial<T> operator - (const U& a, const polynomial<T>& b)
  510. {
  511. polynomial<T> result(a);
  512. result -= b;
  513. return result;
  514. }
  515. template <class U, class T>
  516. inline polynomial<T> operator * (const U& a, const polynomial<T>& b)
  517. {
  518. polynomial<T> result(b);
  519. result *= a;
  520. return result;
  521. }
  522. template <class T>
  523. bool operator == (const polynomial<T> &a, const polynomial<T> &b)
  524. {
  525. return a.data() == b.data();
  526. }
  527. // Unary minus (negate).
  528. template <class T>
  529. polynomial<T> operator - (polynomial<T> a)
  530. {
  531. std::transform(a.data().begin(), a.data().end(), a.data().begin(), std::negate<T>());
  532. return a;
  533. }
  534. template <class charT, class traits, class T>
  535. inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& os, const polynomial<T>& poly)
  536. {
  537. os << "{ ";
  538. for(unsigned i = 0; i < poly.size(); ++i)
  539. {
  540. if(i) os << ", ";
  541. os << poly[i];
  542. }
  543. os << " }";
  544. return os;
  545. }
  546. } // namespace tools
  547. } // namespace math
  548. } // namespace boost
  549. #endif // BOOST_MATH_TOOLS_POLYNOMIAL_HPP