mt2  8bbb7ce09375b7fc0edeb89e1fe1dbb76bbd0555
polynomial.hpp
Go to the documentation of this file.
1 #ifndef H_POLYNOMIAL
2 #define H_POLYNOMIAL
3 
4 #include <vector>
5 
6 namespace{
7  template<typename CoeffType>
8  unsigned GetSignChanges(const std::vector<CoeffType> &coeffs){
9  unsigned num_roots = 0;
10  for(size_t i = 0; i < coeffs.size(); ++i){
11  if(coeffs.at(i) == 0) continue;
12  for(size_t j = i + 1; j < coeffs.size(); ++j){
13  if(coeffs.at(j) == 0){
14  continue;
15  }else{
16  if((coeffs.at(i) < 0 && coeffs.at(j) > 0)
17  || (coeffs.at(i) > 0 && coeffs.at(j) < 0)) ++num_roots;
18  break;
19  }
20  }
21  }
22  return num_roots;
23  }
24 }
25 
26 template<typename CoeffType>
27 class Polynomial{
28 public:
29  Polynomial() = default;
30  Polynomial(const Polynomial &) = default;
31  Polynomial& operator=(const Polynomial &) = default;
32  Polynomial(Polynomial &&) = default;
33  Polynomial& operator=(Polynomial &&) = default;
34  ~Polynomial() = default;
35 
36  Polynomial(const CoeffType &coeff):
37  coeffs_(1, coeff){
38  Shrink();
39  }
40 
41  Polynomial(const std::vector<CoeffType> &coeffs):
42  coeffs_(coeffs){
43  Shrink();
44  }
45 
46  void SetCoefficient(std::size_t degree, CoeffType coefficient){
47  if(degree >= coeffs_.size() && coefficient != 0){
48  coeffs_.resize(degree + 1,0);
49  coeffs_.at(degree) = coefficient;
50  }else if(degree < coeffs_.size()){
51  coeffs_.at(degree) = coefficient;
52  if(coefficient == 0 && degree+1 == coeffs_.size()){
53  Shrink();
54  }
55  }
56  }
57 
58  CoeffType GetCoefficient(std::size_t degree) const{
59  if(degree >= coeffs_.size()) return 0;
60  return coeffs_.at(degree);
61  }
62 
63  CoeffType LeadingCoefficient() const{
64  return coeffs_.size() ? coeffs_.back() : 0;
65  }
66 
67  std::size_t Degree() const{
68  return coeffs_.size() ? coeffs_.size()-1 : 0;
69  }
70 
71  void TruncateToDegree(std::size_t degree){
72  if(degree < Degree()){
73  coeffs_.resize(degree+1,0);
74  Shrink();
75  }
76  }
77 
78  bool IsZero() const{
79  return coeffs_.size() == 0;
80  }
81 
82  operator std::vector<CoeffType>() const{
83  return coeffs_;
84  }
85 
86  template<typename ArgType>
87  auto operator()(const ArgType &x) const -> decltype(CoeffType(0)*x){
88  if(coeffs_.size() == 0) return 0;
89  decltype(coeffs_.at(0)*x) value = coeffs_.back();
90  for(size_t degree = coeffs_.size()-2; degree < coeffs_.size(); --degree){
91  value = value * x + coeffs_.at(degree);
92  }
93  return value;
94  }
95 
97  if(p.coeffs_.size() > coeffs_.size()){
98  coeffs_.resize(p.coeffs_.size(),0);
99  }
100  for(size_t i = 0; i < p.coeffs_.size(); ++i){
101  coeffs_.at(i) += p.coeffs_.at(i);
102  }
103  Shrink();
104  return *this;
105  }
106 
108  if(p.coeffs_.size() > coeffs_.size()){
109  coeffs_.resize(p.coeffs_.size(),0);
110  }
111  for(size_t i = 0; i < p.coeffs_.size(); ++i){
112  coeffs_.at(i) -= p.coeffs_.at(i);
113  }
114  Shrink();
115  return *this;
116  }
117 
119  std::vector<CoeffType> output(Degree()+p.Degree()+1, 0);
120  for(size_t deg_a = 0; deg_a < coeffs_.size(); ++deg_a){
121  for(size_t deg_b = 0; deg_b < p.coeffs_.size(); ++deg_b){
122  output.at(deg_a+deg_b) += coeffs_.at(deg_a)*p.coeffs_.at(deg_b);
123  }
124  }
125  coeffs_ = output;
126  Shrink();
127  return *this;
128  }
129 
131  Polynomial quo;
132  Polynomial rem = *this;
133  while(!rem.IsZero() && rem.Degree()>=p.Degree()){
134  size_t before_deg = rem.Degree();
135  CoeffType t = rem.LeadingCoefficient()/p.LeadingCoefficient();
136  Polynomial term;
137  term.SetCoefficient(rem.Degree()-p.Degree(), t);
138  quo += term;
139  rem -= term*p;
140  rem.TruncateToDegree(before_deg-1);
141  }
142  *this = quo;
143  Shrink();
144  return *this;
145  }
146 
148  Polynomial quo(0);
149  Polynomial rem = *this;
150  size_t pdeg = p.Degree();
151  CoeffType pcoeff_inv = 1./p.LeadingCoefficient();
152  while(!rem.IsZero() && rem.Degree()>=pdeg){
153  size_t before_deg = rem.Degree();
154  CoeffType t = rem.LeadingCoefficient()*pcoeff_inv;
155  Polynomial term;
156  term.SetCoefficient(before_deg-pdeg, t);
157  quo += term;
158  rem -= term*p;
159  if(before_deg == 0){
160  break;
161  }else{
162  rem.TruncateToDegree(before_deg-1);
163  }
164  }
165  *this = rem;
166  Shrink();
167  return *this;
168  }
169 
171  Polynomial out = *this;
172  for(auto &c: out.coeffs_){
173  c = -c;
174  }
175  return out;
176  }
177 
179  return *this;
180  }
181 
182  bool operator!=(const Polynomial &p){
183  return coeffs_!=p.coeffs_;
184  }
185 
186  bool operator==(const Polynomial &p){
187  return coeffs_==p.coeffs_;
188  }
189 
190 private:
191  std::vector<CoeffType> coeffs_;
192 
193  void Shrink(){
194  if(coeffs_.size() == 0) return;
195 
196  bool is_zero = true;
197  size_t degree = 0;
198  for(size_t i = coeffs_.size()-1; i < coeffs_.size() && is_zero; --i){
199  if(coeffs_.at(i) != 0){
200  degree = i;
201  is_zero = false;
202  }
203  }
204 
205  coeffs_.resize(is_zero ? 0 : degree + 1, 0);
206  }
207 };
208 
209 template<typename CoeffType>
211  return a+=b;
212 }
213 
214 template<typename CoeffType>
216  return a-=b;
217 }
218 
219 template<typename CoeffType>
221  return a*=b;
222 }
223 
224 template<typename CoeffType>
226  return a/=b;
227 }
228 
229 template<typename CoeffType>
231  return a%=b;
232 }
233 
234 template<typename CoeffType>
235 std::ostream & operator<<(std::ostream &stream, const Polynomial<CoeffType> &p){
236  stream << "Poly[" << p.Degree() << "](";
237  for(size_t deg = 0; deg < p.Degree(); ++deg){
238  stream << p.GetCoefficient(deg) << ',';
239  }
240  stream << p.GetCoefficient(p.Degree()) << ')';
241  return stream;
242 }
243 
244 template<typename CoeffType>
246  auto coeffs = static_cast<std::vector<CoeffType> >(poly);
247  for(; n != 0; --n){
248  for(size_t from_degree = 1; from_degree < coeffs.size(); ++from_degree){
249  coeffs.at(from_degree-1) = from_degree * coeffs.at(from_degree);
250  }
251  coeffs.pop_back();
252  }
253  return coeffs;
254 }
255 
256 template<typename CoeffType>
257 std::vector<Polynomial<CoeffType> > SturmSequence(const Polynomial<CoeffType> &poly){
258  std::vector<Polynomial<CoeffType> > out(1, poly);
259  if(poly.Degree() == 0) return out;
260  out.push_back(Derivative(poly));
261  size_t i = 0;
262  auto negrem = -(out.at(i) % out.at(i+1));
263  while(!negrem.IsZero()){
264  //DBG(negrem);
265  out.push_back(negrem);
266  ++i;
267  negrem = -(out.at(i) % out.at(i+1));
268  }
269  return out;
270 }
271 
272 template<typename CoeffType>
273 unsigned NumRoots(const Polynomial<CoeffType> &poly){
274  auto sturm = SturmSequence(poly);
275  std::vector<CoeffType> pos_seq, neg_seq;
276  for(const auto &p: sturm){
277  pos_seq.push_back(p.LeadingCoefficient());
278  neg_seq.push_back(p.Degree()%2 == 0 ? p.LeadingCoefficient() : -p.LeadingCoefficient());
279  }
280 
281  int changes_pos = GetSignChanges(pos_seq);
282  int changes_neg = GetSignChanges(neg_seq);
283 
284  return changes_neg - changes_pos;
285 }
286 
287 template<typename CoeffType, typename ArgType = double>
288 unsigned NumRoots(const Polynomial<CoeffType> &poly, const ArgType &low, const ArgType &high){
289  auto sturm = SturmSequence(poly);
290  std::vector<CoeffType> pos_seq, neg_seq;
291  for(const auto &p: sturm){
292  pos_seq.push_back(p(high));
293  neg_seq.push_back(p(low));
294  }
295  int changes_pos = GetSignChanges(pos_seq);
296  int changes_neg = GetSignChanges(neg_seq);
297 
298  return changes_neg - changes_pos;
299 }
300 
301 #endif
CoeffType LeadingCoefficient() const
Definition: polynomial.hpp:63
unsigned NumRoots(const Polynomial< CoeffType > &poly)
Definition: polynomial.hpp:273
Polynomial operator+() const
Definition: polynomial.hpp:178
auto operator()(const ArgType &x) const -> decltype(CoeffType(0)*x)
Definition: polynomial.hpp:87
std::vector< CoeffType > coeffs_
Definition: polynomial.hpp:191
Polynomial & operator=(const Polynomial &)=default
Polynomial< CoeffType > operator*(Polynomial< CoeffType > a, Polynomial< CoeffType > b)
Definition: polynomial.hpp:220
Polynomial & operator-=(const Polynomial &p)
Definition: polynomial.hpp:107
Polynomial()=default
Polynomial & operator*=(const Polynomial &p)
Definition: polynomial.hpp:118
unsigned GetSignChanges(const std::vector< CoeffType > &coeffs)
Definition: polynomial.hpp:8
Polynomial(const std::vector< CoeffType > &coeffs)
Definition: polynomial.hpp:41
std::size_t Degree() const
Definition: polynomial.hpp:67
Polynomial operator-() const
Definition: polynomial.hpp:170
Polynomial & operator/=(const Polynomial &p)
Definition: polynomial.hpp:130
~Polynomial()=default
Polynomial & operator%=(const Polynomial &p)
Definition: polynomial.hpp:147
Polynomial & operator+=(const Polynomial &p)
Definition: polynomial.hpp:96
Polynomial< CoeffType > Derivative(const Polynomial< CoeffType > &poly, size_t n=1)
Definition: polynomial.hpp:245
Polynomial(const CoeffType &coeff)
Definition: polynomial.hpp:36
void TruncateToDegree(std::size_t degree)
Definition: polynomial.hpp:71
Polynomial< CoeffType > operator%(Polynomial< CoeffType > a, Polynomial< CoeffType > b)
Definition: polynomial.hpp:230
Polynomial< CoeffType > operator/(Polynomial< CoeffType > a, Polynomial< CoeffType > b)
Definition: polynomial.hpp:225
bool operator!=(const Polynomial &p)
Definition: polynomial.hpp:182
bool operator==(const Polynomial &p)
Definition: polynomial.hpp:186
void SetCoefficient(std::size_t degree, CoeffType coefficient)
Definition: polynomial.hpp:46
CoeffType GetCoefficient(std::size_t degree) const
Definition: polynomial.hpp:58
bool IsZero() const
Definition: polynomial.hpp:78
std::vector< Polynomial< CoeffType > > SturmSequence(const Polynomial< CoeffType > &poly)
Definition: polynomial.hpp:257
void Shrink()
Definition: polynomial.hpp:193