Chris@16
|
1 // (C) Copyright John Maddock 2006.
|
Chris@16
|
2 // Use, modification and distribution are subject to the
|
Chris@16
|
3 // Boost Software License, Version 1.0. (See accompanying file
|
Chris@16
|
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5
|
Chris@16
|
6 #ifndef BOOST_MATH_TOOLS_POLYNOMIAL_HPP
|
Chris@16
|
7 #define BOOST_MATH_TOOLS_POLYNOMIAL_HPP
|
Chris@16
|
8
|
Chris@16
|
9 #ifdef _MSC_VER
|
Chris@16
|
10 #pragma once
|
Chris@16
|
11 #endif
|
Chris@16
|
12
|
Chris@16
|
13 #include <boost/assert.hpp>
|
Chris@16
|
14 #include <boost/math/tools/rational.hpp>
|
Chris@16
|
15 #include <boost/math/tools/real_cast.hpp>
|
Chris@16
|
16 #include <boost/math/special_functions/binomial.hpp>
|
Chris@16
|
17
|
Chris@16
|
18 #include <vector>
|
Chris@16
|
19 #include <ostream>
|
Chris@16
|
20 #include <algorithm>
|
Chris@16
|
21
|
Chris@16
|
22 namespace boost{ namespace math{ namespace tools{
|
Chris@16
|
23
|
Chris@16
|
24 template <class T>
|
Chris@16
|
25 T chebyshev_coefficient(unsigned n, unsigned m)
|
Chris@16
|
26 {
|
Chris@16
|
27 BOOST_MATH_STD_USING
|
Chris@16
|
28 if(m > n)
|
Chris@16
|
29 return 0;
|
Chris@16
|
30 if((n & 1) != (m & 1))
|
Chris@16
|
31 return 0;
|
Chris@16
|
32 if(n == 0)
|
Chris@16
|
33 return 1;
|
Chris@16
|
34 T result = T(n) / 2;
|
Chris@16
|
35 unsigned r = n - m;
|
Chris@16
|
36 r /= 2;
|
Chris@16
|
37
|
Chris@16
|
38 BOOST_ASSERT(n - 2 * r == m);
|
Chris@16
|
39
|
Chris@16
|
40 if(r & 1)
|
Chris@16
|
41 result = -result;
|
Chris@16
|
42 result /= n - r;
|
Chris@16
|
43 result *= boost::math::binomial_coefficient<T>(n - r, r);
|
Chris@16
|
44 result *= ldexp(1.0f, m);
|
Chris@16
|
45 return result;
|
Chris@16
|
46 }
|
Chris@16
|
47
|
Chris@16
|
48 template <class Seq>
|
Chris@16
|
49 Seq polynomial_to_chebyshev(const Seq& s)
|
Chris@16
|
50 {
|
Chris@16
|
51 // Converts a Polynomial into Chebyshev form:
|
Chris@16
|
52 typedef typename Seq::value_type value_type;
|
Chris@16
|
53 typedef typename Seq::difference_type difference_type;
|
Chris@16
|
54 Seq result(s);
|
Chris@16
|
55 difference_type order = s.size() - 1;
|
Chris@16
|
56 difference_type even_order = order & 1 ? order - 1 : order;
|
Chris@16
|
57 difference_type odd_order = order & 1 ? order : order - 1;
|
Chris@16
|
58
|
Chris@16
|
59 for(difference_type i = even_order; i >= 0; i -= 2)
|
Chris@16
|
60 {
|
Chris@16
|
61 value_type val = s[i];
|
Chris@16
|
62 for(difference_type k = even_order; k > i; k -= 2)
|
Chris@16
|
63 {
|
Chris@16
|
64 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
|
Chris@16
|
65 }
|
Chris@16
|
66 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
|
Chris@16
|
67 result[i] = val;
|
Chris@16
|
68 }
|
Chris@16
|
69 result[0] *= 2;
|
Chris@16
|
70
|
Chris@16
|
71 for(difference_type i = odd_order; i >= 0; i -= 2)
|
Chris@16
|
72 {
|
Chris@16
|
73 value_type val = s[i];
|
Chris@16
|
74 for(difference_type k = odd_order; k > i; k -= 2)
|
Chris@16
|
75 {
|
Chris@16
|
76 val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
|
Chris@16
|
77 }
|
Chris@16
|
78 val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
|
Chris@16
|
79 result[i] = val;
|
Chris@16
|
80 }
|
Chris@16
|
81 return result;
|
Chris@16
|
82 }
|
Chris@16
|
83
|
Chris@16
|
84 template <class Seq, class T>
|
Chris@16
|
85 T evaluate_chebyshev(const Seq& a, const T& x)
|
Chris@16
|
86 {
|
Chris@16
|
87 // Clenshaw's formula:
|
Chris@16
|
88 typedef typename Seq::difference_type difference_type;
|
Chris@16
|
89 T yk2 = 0;
|
Chris@16
|
90 T yk1 = 0;
|
Chris@16
|
91 T yk = 0;
|
Chris@16
|
92 for(difference_type i = a.size() - 1; i >= 1; --i)
|
Chris@16
|
93 {
|
Chris@16
|
94 yk2 = yk1;
|
Chris@16
|
95 yk1 = yk;
|
Chris@16
|
96 yk = 2 * x * yk1 - yk2 + a[i];
|
Chris@16
|
97 }
|
Chris@16
|
98 return a[0] / 2 + yk * x - yk1;
|
Chris@16
|
99 }
|
Chris@16
|
100
|
Chris@16
|
101 template <class T>
|
Chris@16
|
102 class polynomial
|
Chris@16
|
103 {
|
Chris@16
|
104 public:
|
Chris@16
|
105 // typedefs:
|
Chris@16
|
106 typedef typename std::vector<T>::value_type value_type;
|
Chris@16
|
107 typedef typename std::vector<T>::size_type size_type;
|
Chris@16
|
108
|
Chris@16
|
109 // construct:
|
Chris@16
|
110 polynomial(){}
|
Chris@16
|
111 template <class U>
|
Chris@16
|
112 polynomial(const U* data, unsigned order)
|
Chris@16
|
113 : m_data(data, data + order + 1)
|
Chris@16
|
114 {
|
Chris@16
|
115 }
|
Chris@16
|
116 template <class U>
|
Chris@16
|
117 polynomial(const U& point)
|
Chris@16
|
118 {
|
Chris@16
|
119 m_data.push_back(point);
|
Chris@16
|
120 }
|
Chris@16
|
121
|
Chris@16
|
122 // copy:
|
Chris@16
|
123 polynomial(const polynomial& p)
|
Chris@16
|
124 : m_data(p.m_data) { }
|
Chris@16
|
125
|
Chris@16
|
126 template <class U>
|
Chris@16
|
127 polynomial(const polynomial<U>& p)
|
Chris@16
|
128 {
|
Chris@16
|
129 for(unsigned i = 0; i < p.size(); ++i)
|
Chris@16
|
130 {
|
Chris@16
|
131 m_data.push_back(boost::math::tools::real_cast<T>(p[i]));
|
Chris@16
|
132 }
|
Chris@16
|
133 }
|
Chris@16
|
134
|
Chris@16
|
135 // access:
|
Chris@16
|
136 size_type size()const { return m_data.size(); }
|
Chris@16
|
137 size_type degree()const { return m_data.size() - 1; }
|
Chris@16
|
138 value_type& operator[](size_type i)
|
Chris@16
|
139 {
|
Chris@16
|
140 return m_data[i];
|
Chris@16
|
141 }
|
Chris@16
|
142 const value_type& operator[](size_type i)const
|
Chris@16
|
143 {
|
Chris@16
|
144 return m_data[i];
|
Chris@16
|
145 }
|
Chris@16
|
146 T evaluate(T z)const
|
Chris@16
|
147 {
|
Chris@16
|
148 return boost::math::tools::evaluate_polynomial(&m_data[0], z, m_data.size());;
|
Chris@16
|
149 }
|
Chris@16
|
150 std::vector<T> chebyshev()const
|
Chris@16
|
151 {
|
Chris@16
|
152 return polynomial_to_chebyshev(m_data);
|
Chris@16
|
153 }
|
Chris@16
|
154
|
Chris@16
|
155 // operators:
|
Chris@16
|
156 template <class U>
|
Chris@16
|
157 polynomial& operator +=(const U& value)
|
Chris@16
|
158 {
|
Chris@16
|
159 if(m_data.size() == 0)
|
Chris@16
|
160 m_data.push_back(value);
|
Chris@16
|
161 else
|
Chris@16
|
162 {
|
Chris@16
|
163 m_data[0] += value;
|
Chris@16
|
164 }
|
Chris@16
|
165 return *this;
|
Chris@16
|
166 }
|
Chris@16
|
167 template <class U>
|
Chris@16
|
168 polynomial& operator -=(const U& value)
|
Chris@16
|
169 {
|
Chris@16
|
170 if(m_data.size() == 0)
|
Chris@16
|
171 m_data.push_back(-value);
|
Chris@16
|
172 else
|
Chris@16
|
173 {
|
Chris@16
|
174 m_data[0] -= value;
|
Chris@16
|
175 }
|
Chris@16
|
176 return *this;
|
Chris@16
|
177 }
|
Chris@16
|
178 template <class U>
|
Chris@16
|
179 polynomial& operator *=(const U& value)
|
Chris@16
|
180 {
|
Chris@16
|
181 for(size_type i = 0; i < m_data.size(); ++i)
|
Chris@16
|
182 m_data[i] *= value;
|
Chris@16
|
183 return *this;
|
Chris@16
|
184 }
|
Chris@16
|
185 template <class U>
|
Chris@16
|
186 polynomial& operator +=(const polynomial<U>& value)
|
Chris@16
|
187 {
|
Chris@16
|
188 size_type s1 = (std::min)(m_data.size(), value.size());
|
Chris@16
|
189 for(size_type i = 0; i < s1; ++i)
|
Chris@16
|
190 m_data[i] += value[i];
|
Chris@16
|
191 for(size_type i = s1; i < value.size(); ++i)
|
Chris@16
|
192 m_data.push_back(value[i]);
|
Chris@16
|
193 return *this;
|
Chris@16
|
194 }
|
Chris@16
|
195 template <class U>
|
Chris@16
|
196 polynomial& operator -=(const polynomial<U>& value)
|
Chris@16
|
197 {
|
Chris@16
|
198 size_type s1 = (std::min)(m_data.size(), value.size());
|
Chris@16
|
199 for(size_type i = 0; i < s1; ++i)
|
Chris@16
|
200 m_data[i] -= value[i];
|
Chris@16
|
201 for(size_type i = s1; i < value.size(); ++i)
|
Chris@16
|
202 m_data.push_back(-value[i]);
|
Chris@16
|
203 return *this;
|
Chris@16
|
204 }
|
Chris@16
|
205 template <class U>
|
Chris@16
|
206 polynomial& operator *=(const polynomial<U>& value)
|
Chris@16
|
207 {
|
Chris@16
|
208 // TODO: FIXME: use O(N log(N)) algorithm!!!
|
Chris@16
|
209 BOOST_ASSERT(value.size());
|
Chris@16
|
210 polynomial base(*this);
|
Chris@16
|
211 *this *= value[0];
|
Chris@16
|
212 for(size_type i = 1; i < value.size(); ++i)
|
Chris@16
|
213 {
|
Chris@16
|
214 polynomial t(base);
|
Chris@16
|
215 t *= value[i];
|
Chris@16
|
216 size_type s = size() - i;
|
Chris@16
|
217 for(size_type j = 0; j < s; ++j)
|
Chris@16
|
218 {
|
Chris@16
|
219 m_data[i+j] += t[j];
|
Chris@16
|
220 }
|
Chris@16
|
221 for(size_type j = s; j < t.size(); ++j)
|
Chris@16
|
222 m_data.push_back(t[j]);
|
Chris@16
|
223 }
|
Chris@16
|
224 return *this;
|
Chris@16
|
225 }
|
Chris@16
|
226
|
Chris@16
|
227 private:
|
Chris@16
|
228 std::vector<T> m_data;
|
Chris@16
|
229 };
|
Chris@16
|
230
|
Chris@16
|
231 template <class T>
|
Chris@16
|
232 inline polynomial<T> operator + (const polynomial<T>& a, const polynomial<T>& b)
|
Chris@16
|
233 {
|
Chris@16
|
234 polynomial<T> result(a);
|
Chris@16
|
235 result += b;
|
Chris@16
|
236 return result;
|
Chris@16
|
237 }
|
Chris@16
|
238
|
Chris@16
|
239 template <class T>
|
Chris@16
|
240 inline polynomial<T> operator - (const polynomial<T>& a, const polynomial<T>& b)
|
Chris@16
|
241 {
|
Chris@16
|
242 polynomial<T> result(a);
|
Chris@16
|
243 result -= b;
|
Chris@16
|
244 return result;
|
Chris@16
|
245 }
|
Chris@16
|
246
|
Chris@16
|
247 template <class T>
|
Chris@16
|
248 inline polynomial<T> operator * (const polynomial<T>& a, const polynomial<T>& b)
|
Chris@16
|
249 {
|
Chris@16
|
250 polynomial<T> result(a);
|
Chris@16
|
251 result *= b;
|
Chris@16
|
252 return result;
|
Chris@16
|
253 }
|
Chris@16
|
254
|
Chris@16
|
255 template <class T, class U>
|
Chris@16
|
256 inline polynomial<T> operator + (const polynomial<T>& a, const U& b)
|
Chris@16
|
257 {
|
Chris@16
|
258 polynomial<T> result(a);
|
Chris@16
|
259 result += b;
|
Chris@16
|
260 return result;
|
Chris@16
|
261 }
|
Chris@16
|
262
|
Chris@16
|
263 template <class T, class U>
|
Chris@16
|
264 inline polynomial<T> operator - (const polynomial<T>& a, const U& b)
|
Chris@16
|
265 {
|
Chris@16
|
266 polynomial<T> result(a);
|
Chris@16
|
267 result -= b;
|
Chris@16
|
268 return result;
|
Chris@16
|
269 }
|
Chris@16
|
270
|
Chris@16
|
271 template <class T, class U>
|
Chris@16
|
272 inline polynomial<T> operator * (const polynomial<T>& a, const U& b)
|
Chris@16
|
273 {
|
Chris@16
|
274 polynomial<T> result(a);
|
Chris@16
|
275 result *= b;
|
Chris@16
|
276 return result;
|
Chris@16
|
277 }
|
Chris@16
|
278
|
Chris@16
|
279 template <class U, class T>
|
Chris@16
|
280 inline polynomial<T> operator + (const U& a, const polynomial<T>& b)
|
Chris@16
|
281 {
|
Chris@16
|
282 polynomial<T> result(b);
|
Chris@16
|
283 result += a;
|
Chris@16
|
284 return result;
|
Chris@16
|
285 }
|
Chris@16
|
286
|
Chris@16
|
287 template <class U, class T>
|
Chris@16
|
288 inline polynomial<T> operator - (const U& a, const polynomial<T>& b)
|
Chris@16
|
289 {
|
Chris@16
|
290 polynomial<T> result(a);
|
Chris@16
|
291 result -= b;
|
Chris@16
|
292 return result;
|
Chris@16
|
293 }
|
Chris@16
|
294
|
Chris@16
|
295 template <class U, class T>
|
Chris@16
|
296 inline polynomial<T> operator * (const U& a, const polynomial<T>& b)
|
Chris@16
|
297 {
|
Chris@16
|
298 polynomial<T> result(b);
|
Chris@16
|
299 result *= a;
|
Chris@16
|
300 return result;
|
Chris@16
|
301 }
|
Chris@16
|
302
|
Chris@16
|
303 template <class charT, class traits, class T>
|
Chris@16
|
304 inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& os, const polynomial<T>& poly)
|
Chris@16
|
305 {
|
Chris@16
|
306 os << "{ ";
|
Chris@16
|
307 for(unsigned i = 0; i < poly.size(); ++i)
|
Chris@16
|
308 {
|
Chris@16
|
309 if(i) os << ", ";
|
Chris@16
|
310 os << poly[i];
|
Chris@16
|
311 }
|
Chris@16
|
312 os << " }";
|
Chris@16
|
313 return os;
|
Chris@16
|
314 }
|
Chris@16
|
315
|
Chris@16
|
316 } // namespace tools
|
Chris@16
|
317 } // namespace math
|
Chris@16
|
318 } // namespace boost
|
Chris@16
|
319
|
Chris@16
|
320 #endif // BOOST_MATH_TOOLS_POLYNOMIAL_HPP
|
Chris@16
|
321
|
Chris@16
|
322
|
Chris@16
|
323
|