Virtual Testbed
Ship dynamics simulator for extreme conditions
polynomial.hh
1 #ifndef VTESTBED_CORE_POLYNOMIAL_HH
2 #define VTESTBED_CORE_POLYNOMIAL_HH
3 
4 #include <algorithm>
5 #include <complex>
6 #include <initializer_list>
7 #include <type_traits>
8 
9 #include <vtestbed/base/blitz.hh>
10 #include <vtestbed/core/math.hh>
11 
12 namespace vtb {
13 
14  namespace core {
15 
16  template <class T>
17  struct is_complex: public std::false_type {};
18 
19  template <class T>
20  struct is_complex<std::complex<T>>: public std::true_type {};
21 
22 
23  template <class T>
24  class Polynomial {
25 
26  public:
27  typedef blitz::Array<T,1> array_type;
28  typedef T value_type;
29  typedef value_type* pointer;
30  typedef const value_type* const_pointer;
31  typedef typename std::conditional<
35  >::type complex_polynomial;
36  typedef typename std::conditional<
38  blitz::Array<T,1>,
39  blitz::Array<std::complex<T>,1>
40  >::type complex_array;
41 
42  private:
43  array_type _coefficients;
44 
45  public:
46 
47  Polynomial() = default;
48 
49  inline explicit
50  Polynomial(int size, const T& value = T{0}):
51  _coefficients(size) {
52  _coefficients = value;
53  }
54 
55  inline explicit
56  Polynomial(array_type coefs):
57  _coefficients{coefs} {}
58 
59  inline
61  _coefficients(coefs.size()) {
62  std::copy(coefs.begin(), coefs.end(), this->begin());
63  }
64 
65  inline
66  Polynomial(const Polynomial& rhs):
67  _coefficients{rhs._coefficients.copy()} {}
68 
69  inline Polynomial&
70  operator=(const Polynomial& rhs) {
71  this->_coefficients.reference(rhs._coefficients.copy());
72  return *this;
73  }
74 
75  inline
76  Polynomial(Polynomial&& rhs) {
77  this->_coefficients.reference(rhs._coefficients);
78  }
79 
80  inline Polynomial&
81  operator=(Polynomial&& rhs) {
82  this->swap(rhs);
83  return *this;
84  }
85 
86  ~Polynomial() = default;
87 
88  inline value_type
89  evaluate(value_type x) const {
90  value_type result{0};
91  const_pointer last = this->begin()-1;
92  const_pointer first = this->end()-1;
93  while (first != last) {
94  result = fma(result, x, *first);
95  --first;
96  }
97  return result;
98  }
99 
100  inline value_type
101  operator()(value_type x) const {
102  return this->evaluate(x);
103  }
104 
105  inline const value_type&
106  operator[](int i) const noexcept {
107  return this->_coefficients(i);
108  }
109 
110  inline value_type&
111  operator[](int i) noexcept {
112  return this->_coefficients(i);
113  }
114 
115  inline const_pointer
116  begin() const noexcept {
117  return this->_coefficients.data();
118  }
119 
120  inline pointer
121  begin() noexcept {
122  return this->_coefficients.data();
123  }
124 
125  inline const_pointer
126  end() const noexcept {
127  return this->_coefficients.data() + this->size();
128  }
129 
130  inline pointer
131  end() noexcept {
132  return this->_coefficients.data() + this->size();
133  }
134 
135  inline int
136  size() const noexcept {
137  return this->_coefficients.extent(0);
138  }
139 
140  inline int
141  order() const noexcept {
142  return std::max(0, this->size() - 1);
143  }
144 
145  inline void
146  swap(Polynomial& rhs) {
147  blitz::swap(this->_coefficients, rhs._coefficients);
148  }
149 
150  inline const array_type&
151  coefficients() const noexcept {
152  return this->_coefficients;
153  }
154 
155  inline array_type&
156  coefficients() noexcept {
157  return this->_coefficients;
158  }
159 
160  inline const value_type&
161  coefficients(int i) const noexcept {
162  return this->_coefficients(i);
163  }
164 
165  inline value_type&
166  coefficients(int i) noexcept {
167  return this->_coefficients(i);
168  }
169 
170  inline complex_polynomial
171  reciprocal() const {
172  complex_polynomial result(this->size());
173  const int n = this->size();
174  for (int i=0; i<n; ++i) {
175  result[i] = std::conj((*this)[n-1-i]);
176  }
177  return result;
178  }
179 
180  friend inline Polynomial
181  operator*(const Polynomial& lhs, const T& rhs) {
182  return Polynomial(lhs._coefficients * rhs);
183  }
184 
185  friend inline Polynomial
186  operator*(const T& lhs, const Polynomial& rhs) {
187  return Polynomial(lhs * rhs._coefficients);
188  }
189 
190  friend inline Polynomial
191  operator/(const Polynomial& lhs, const T& rhs) {
192  return Polynomial(lhs._coefficients / rhs);
193  }
194 
195  friend inline Polynomial
196  operator+(const Polynomial& lhs, const Polynomial& rhs) {
197  using blitz::Range;
198  Polynomial result;
199  if (lhs.size() < rhs.size()) {
200  result = rhs;
201  Range r{0,lhs.size()-1};
202  result._coefficients(r) += lhs._coefficients;
203  } else {
204  result = lhs;
205  Range r{0,rhs.size()-1};
206  result._coefficients(r) += rhs._coefficients;
207  }
208  return result;
209  }
210 
211  friend inline Polynomial
212  operator-(const Polynomial& lhs, const Polynomial& rhs) {
213  using blitz::Range;
214  Polynomial result;
215  if (lhs.size() < rhs.size()) {
216  result = rhs;
217  Range r{0,lhs.size()-1};
218  result._coefficients(r) -= lhs._coefficients;
219  } else {
220  result = lhs;
221  Range r{0,rhs.size()-1};
222  result._coefficients(r) -= rhs._coefficients;
223  }
224  return result;
225  }
226 
227  };
228 
229  template <class T>
230  inline void
231  swap(Polynomial<T>& lhs, Polynomial<T>& rhs) {
232  lhs.swap(rhs);
233  }
234 
241  template <class T>
242  inline auto
245  const int n = p.size();
246  Polynomial<T> result(n-1);
247  const T conj_a_0 = std::conj(p[0]);
248  const T a_n = p[n-1];
249  for (int i=0; i<n-1; ++i) {
250  result[i] = conj_a_0*p[i] - a_n*std::conj(p[n-1-i]);
251  }
252  return result;
253  }
254 
261  template <class T>
262  inline auto
263  schur_transform(const Polynomial<T>& p)
264  -> typename std::enable_if<!is_complex<T>::value, Polynomial<T>>::type {
265  const int n = p.size();
266  Polynomial<T> result(n-1);
267  const T a_0 = p[0];
268  const T a_n = p[n-1];
269  for (int i=0; i<n-1; ++i) {
270  result[i] = a_0*p[i] - a_n*p[n-1-i];
271  }
272  return result;
273  }
274 
284  template <class T>
285  inline int
287  using blitz::all;
288  int n = p.size();
289  typedef decltype(std::real(p[0])) Real;
290  blitz::Array<Real,1> mask(n);
291  int negative_degree = 0;
292  bool negative_multiple_times = false;
293  for (int i=0; i<n-1; ++i) {
294  p = schur_transform<T>(p);
295  Real delta = std::real(p[0]);
296  mask(i) = delta;
297  #if defined(VTB_DEBUG_SCHUR_COHN)
298  std::clog << "delta=" << delta << std::endl;
299  #endif
300  if (delta < 0) {
301  if (negative_degree == 0) {
302  negative_degree = p.size();
303  } else {
304  negative_multiple_times = true;
305  }
306  }
307  }
308  if (negative_degree == 0) {
309  return 0;
310  }
311  if (!negative_multiple_times) {
312  return negative_degree;
313  }
314  return -1;
315  }
316 
317  }
318 
319 }
320 
321 #endif // vim:filetype=cpp
auto schur_transform(const Polynomial< T > &p) -> typename std::enable_if< is_complex< T >::value, Polynomial< T >>::type
Schur transform for polynomials with complex coefficients.
Definition: polynomial.hh:243
Main namespace.
Definition: convert.hh:9
int num_roots_inside_unit_disk(Polynomial< T > p)
Finds the number of polynomial roots inside the unit disk.
Definition: polynomial.hh:286