UtilsLite
Utilities for C++ programming
Loading...
Searching...
No Matches
Utils_Poly.hh
Go to the documentation of this file.
1/*--------------------------------------------------------------------------*\
2 | |
3 | Copyright (C) 2022 |
4 | |
5 | , __ , __ |
6 | /|/ \ /|/ \ |
7 | | __/ _ ,_ | __/ _ ,_ |
8 | | \|/ / | | | | \|/ / | | | |
9 | |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
10 | /| /| |
11 | \| \| |
12 | |
13 | Enrico Bertolazzi |
14 | Dipartimento di Ingegneria Industriale |
15 | Università degli Studi di Trento |
16 | email: enrico.bertolazzi@unitn.it |
17 | |
18\*--------------------------------------------------------------------------*/
19
20//
21// file: Utils_Poly.hh
22//
23
24#pragma once
25
26#ifndef UTILS_POLY_dot_HH
27#define UTILS_POLY_dot_HH
28
29#ifndef DOXYGEN_SHOULD_SKIP_THIS
30
31#include <iostream>
32#include <sstream>
33#include <string>
34#include <vector>
35#include <algorithm>
36
37#include "Utils_eigen.hh"
38#include "Utils_AlgoBracket.hh"
39
40#endif
41
42namespace Utils {
43
44 using std::string;
45 using std::vector;
46
106 template <typename Real>
107 class Poly : public Eigen::Matrix<Real,Eigen::Dynamic,1> {
108 public:
109 using Integer = int;
110 using dvec_t = Eigen::Matrix<Real,Eigen::Dynamic,1>;
112
113 private:
114 Integer m_order;
115 dvec_t & to_eigen() { return *static_cast<dvec_t*>(this); }
116
117 public:
118
119 Poly() : m_order(0) {}
120
128 explicit
129 Poly( int order ) : m_order(order) {
130 this->resize(order);
131 this->setZero();
132 }
133
140 Poly( Poly_t const & c )
141 : m_order( c.m_order )
142 { *this = c; }
143
157 explicit
158 Poly( dvec_t const & c ) {
159 this->resize( c.size() );
160 // per evitare la ricorsione devo chiamare esplicitamente
161 // l'operatore = della classe di base.
162 this->dvec_t::operator = (c);
163 m_order = Integer(c.size());
164 }
165
177 dvec_t const &
178 to_eigen() const
179 { return * static_cast<dvec_t const *>(this); }
180
203 void
205 m_order = order;
206 this->resize( order );
207 this->setZero();
208 }
209
232 void
234 m_order = degree+1;
235 this->resize( m_order );
236 this->setZero();
237 }
238
261 Poly_t & set_scalar( Real a );
262
287 Poly_t & set_monomial( Real a );
288
306 dvec_t coeffs() const { return to_eigen(); }
307
325 Integer degree() const { return m_order - 1; }
326
345 Integer order() const { return m_order; }
346
382 string to_string() const;
383
411 Real eval( Real x ) const;
412
447 Real eval_D( Real x ) const;
448
491 void eval( Real x, Real & p, Real & Dp ) const;
492
513 Real leading_coeff() const { return this->coeff(m_order-1); }
514
539 void derivative( Poly_t & result ) const;
540
566 void integral( Poly_t & result ) const;
567
596 Real normalize();
597
625 void purge( Real epsi );
626
654
677
701 void
703 this->to_eigen() /= this->coeff(m_order-1);
704 this->coeffRef(m_order-1) = 1;
705 }
706
726 Poly_t & operator = ( Poly_t const & c );
727
746 Poly_t operator-() { return Poly(-this->to_eigen()); }
747
768 Poly_t & operator += ( Poly_t const & q );
769
790 Poly_t & operator -= ( Poly_t const & q );
791
813 Poly_t & operator *= ( Poly_t const & q );
814
834 Poly_t & operator += ( Real a );
835
856 Poly_t & operator -= ( Real a );
857
878 Poly_t & operator *= ( Real a );
879
880 };
881
904 template <typename Real>
905 class Sturm {
906 public:
907 using Integer = int;
909 using dvec_t = Eigen::Matrix<Real,Eigen::Dynamic,1>;
910
911 using Interval = struct Interval {
912 Real a;
913 Real b;
914 Integer va;
915 Integer vb;
916 bool a_on_root;
917 bool b_on_root;
918 };
919
920 #ifndef DOXYGEN_SHOULD_SKIP_THIS
921 class Bracket_fun : public Bracket_base_fun<Real> {
922 Poly<Real> const * P = nullptr;
923 public:
924 void setup( Poly<Real> const * Pin ) { P = Pin; }
925 Real eval( Real x ) const override { return P->eval(x); }
926 };
927 #endif
928
929 private:
930
931 AlgoBracket<Real> m_solver;
932 Bracket_fun m_fun;
933
934 vector<Poly_t> m_sturm;
935 vector<Interval> m_intervals;
936 dvec_t m_roots;
937 Real m_a{0};
938 Real m_b{0};
939
940 public:
941
942 Sturm() {}
943
960 void build( Poly_t const & p );
961
974 Integer length() const { return Integer(m_sturm.size()); }
975
1007 Poly_t const & get( Integer i ) const { return m_sturm[i]; }
1008
1041 Integer sign_variations( Real x, bool & on_root ) const;
1042
1069 Integer separate_roots( Real a, Real b );
1070
1097
1118 Integer n_roots() const { return Integer(m_intervals.size()); }
1119
1128 Real a() const { return m_a; }
1129
1138 Real b() const { return m_b; }
1139
1150 Interval const & get_interval( Integer i ) const { return m_intervals[i]; }
1151
1173
1192 dvec_t const & roots() const { return m_roots; }
1193
1194 };
1195
1196 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1197
1198 /*
1199 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1200 */
1201 template <typename Real>
1202 Poly<Real> operator + ( Poly<Real> const & a, Poly<Real> const & b );
1203
1204 /*
1205 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1206 */
1207 template <typename Real>
1208 Poly<Real> operator + ( Poly<Real> const & a, Real b );
1209
1210 /*
1211 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1212 */
1213 template <typename Real>
1214 Poly<Real> operator + ( Real a, Poly<Real> const & b );
1215
1216 /*
1217 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1218 */
1219 template <typename Real>
1220 Poly<Real> operator - ( Poly<Real> const & a, Poly<Real> const & b );
1221
1222 /*
1223 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1224 */
1225 template <typename Real>
1226 Poly<Real> operator - ( Poly<Real> const & a, Real b );
1227
1228 /*
1229 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1230 */
1231 template <typename Real>
1232 Poly<Real> operator - ( Real a, Poly<Real> const & b );
1233
1234 /*
1235 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1236 */
1237 template <typename Real>
1238 Poly<Real> operator * ( Poly<Real> const & a, Poly<Real> const & b );
1239
1240 /*
1241 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1242 */
1243 template <typename Real>
1244 Poly<Real> operator * ( Real a, Poly<Real> const & b );
1245
1246 /*
1247 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1248 */
1249 template <typename Real>
1250 Poly<Real> operator * ( Poly<Real> const & a, Real b );
1251
1252 /*
1253 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1254 */
1255
1256 template <typename Real>
1257 void divide(
1258 Poly<Real> const & p,
1259 Poly<Real> const & q,
1260 Poly<Real> & M,
1261 Poly<Real> & R
1262 );
1263
1264 /*
1265 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1266 */
1267 template <typename Real>
1268 void
1269 GCD(
1270 Poly<Real> const & p,
1271 Poly<Real> const & q,
1272 Poly<Real> & g,
1273 Real epsi = 1e-20
1274 );
1275
1276 #endif
1277
1278 /*
1279 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1280 */
1281 template <typename Real>
1282 inline
1283 string
1285
1286 if ( this->order() <= 0 ) return "EMPTY!";
1287 if ( this->order() == 1 ) return fmt::format( "{}", this->coeff(0) );
1288 if ( (*this).cwiseAbs().maxCoeff() == 0 ) return "0";
1289
1290 bool empty = true; // true indica che i coefficienti finora sono nulli
1291 string s = ""; // segno
1292 Real c = 0; // coefficiente
1293 string e = ""; // esponente
1294 string res = "";
1295
1296 // controlla se esiste il primo coefficiente (grado 0)
1297 if ( this->coeff(0) != 0 ) {
1298 res = fmt::format( "{}", this->coeff(0) );
1299 empty = false;
1300 }
1301
1302 for ( typename Poly<Real>::Integer i=1; i < this->order(); ++i ) {
1303 // se il coefficiente e` negativo...
1304 if ( this->coeff(i) < 0 ) {
1305 // e se i coefficienti precenti erano nulli...
1306 if ( empty ) {
1307 s = ""; // ...non scrive il segno
1308 c = this->coeff(i);
1309 empty = false;
1310 } else {
1311 s = " - "; // ...altrimenti scrive il segno come separatore
1312 c = -this->coeff(i); // e inverte il segno del coefficiente
1313 }
1314
1315 // se il coefficiente e` positivo...
1316 } else if ( this->coeff(i) > 0 ) {
1317 c = this->coeff(i);
1318 // e se i coefficienti precenti erano nulli...
1319 if ( empty ) {
1320 s = ""; // ...non scrive il segno
1321 empty = false;
1322 } else {
1323 s = " + "; // ...altrimenti scrive il segno come separatore
1324 }
1325
1326 // se il coefficiente e` zero...
1327 } else {
1328 continue; // ...procede al prossimo
1329 }
1330
1331 // se il grado e` 1 non scrive l'esponente
1332 if ( i == 1 ) e = "x";
1333 else e = fmt::format( "x^{}", i );
1334
1335 // se il coeff è 1 non lo stampo
1336 if ( c == 1 ) { res += s; res += e; }
1337 else res += fmt::format( "{}{} {}", s, c, e );
1338 }
1339 return res;
1340 }
1341
1342 /*
1343 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1344 */
1345 template <typename Real, typename Char>
1346 inline
1347 std::basic_ostream<Char> &
1348 operator << ( std::basic_ostream<Char> & output, Poly<Real> const & p ) {
1349 output << p.to_string();
1350 return output;
1351 }
1352
1353 /*
1354 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1355 */
1356 template <typename Real, typename Char>
1357 inline
1358 std::basic_ostream<Char> &
1359 operator << ( std::basic_ostream<Char> & output, Sturm<Real> const & S ) {
1360 using Integer = typename Poly<Real>::Integer;
1361 output << "Sturm sequence\n";
1362 for ( Integer i = 0; i < S.length(); ++i )
1363 output << "P_" << i << "(x) = " << S.get(i) << '\n';
1364
1365 Integer n = S.n_roots();
1366 if ( n > 0 ) {
1367 fmt::print( output, "roots separation for interval [{},{}]\n", S.a(), S.b() );
1368 for ( Integer i = 0; i < n; ++i ) {
1369 typename Sturm<Real>::Interval const & I = S.get_interval( i );
1370 fmt::print( output, "I = [{}, {}], V = [{}, {}]\n", I.a, I.b, I.va, I.vb );
1371 }
1372 }
1373 return output;
1374 }
1375
1376 /*
1377 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1378 */
1379
1380 #ifndef UTILS_OS_WINDOWS
1381 extern template class Poly<float>;
1382 extern template class Sturm<float>;
1383 extern template class Poly<double>;
1384 extern template class Sturm<double>;
1385 #endif
1386
1387}
1388
1389#ifndef DOXYGEN_SHOULD_SKIP_THIS
1390
1391namespace fmt {
1392 template <typename Real> struct formatter<Utils::Poly<Real>> : ostream_formatter {};
1393 template <typename Real> struct formatter<Utils::Sturm<Real>> : ostream_formatter {};
1394}
1395
1396#endif
1397
1398#endif
1399
1400//
1401// eof: Utils_Poly.hh
1402//
Abstract base class for defining mathematical functions used in the Bracket search algorithm.
Definition Utils_AlgoBracket.hh:83
Specializes the Eigen::Matrix class to represent and manipulate polynomials.
Definition Utils_Poly.hh:107
Poly(Poly_t const &c)
Definition Utils_Poly.hh:140
dvec_t const & to_eigen() const
Definition Utils_Poly.hh:178
void adjust_degree()
void integral(Poly_t &result) const
Poly_t & operator-=(Poly_t const &q)
void set_degree(Integer degree)
Definition Utils_Poly.hh:233
Integer sign_variations() const
Real eval_D(Real x) const
Real eval(Real x) const
Poly_t & operator*=(Poly_t const &q)
Poly_t & operator+=(Poly_t const &q)
Poly()
Definition Utils_Poly.hh:119
Poly(dvec_t const &c)
Definition Utils_Poly.hh:158
Poly_t & set_scalar(Real a)
void make_monic()
Definition Utils_Poly.hh:702
Poly< Real > Poly_t
Definition Utils_Poly.hh:111
void set_order(Integer order)
Definition Utils_Poly.hh:204
Real leading_coeff() const
Definition Utils_Poly.hh:513
Integer degree() const
Definition Utils_Poly.hh:325
Poly_t & set_monomial(Real a)
Poly_t & operator=(Poly_t const &c)
int Integer
Definition Utils_Poly.hh:109
Integer order() const
Definition Utils_Poly.hh:345
void purge(Real epsi)
Poly(int order)
Definition Utils_Poly.hh:129
Real normalize()
void derivative(Poly_t &result) const
string to_string() const
Definition Utils_Poly.hh:1284
dvec_t coeffs() const
Definition Utils_Poly.hh:306
Poly_t operator-()
Definition Utils_Poly.hh:746
Eigen::Matrix< Real, Eigen::Dynamic, 1 > dvec_t
Definition Utils_Poly.hh:110
void eval(Real x, Real &p, Real &Dp) const
Class for managing and computing the Sturm sequence associated with a polynomial.
Definition Utils_Poly.hh:905
struct Interval { Real a; Real b; Integer va; Integer vb; bool a_on_root; bool b_on_root; } Interval
Definition Utils_Poly.hh:911
Integer separate_roots(Real a, Real b)
Computes subintervals containing single roots within a given interval .
Integer sign_variations(Real x, bool &on_root) const
Computes the sign variations of the stored Sturm sequence at a given point .
Poly_t const & get(Integer i) const
Retrieves the i-th polynomial of the stored Sturm sequence.
Definition Utils_Poly.hh:1007
Poly< Real > Poly_t
Definition Utils_Poly.hh:908
Interval const & get_interval(Integer i) const
Returns the i-th interval containing a single root.
Definition Utils_Poly.hh:1150
Integer separate_roots()
Compute an interval that contains all real roots and separate them into subintervals.
Integer n_roots() const
Returns the number of roots found by the Sturm sequence.
Definition Utils_Poly.hh:1118
Integer length() const
Retrieves the length of the stored Sturm sequence.
Definition Utils_Poly.hh:974
dvec_t const & roots() const
Returns a vector containing the computed roots after refinement.
Definition Utils_Poly.hh:1192
void build(Poly_t const &p)
Constructs the Sturm sequence for a given polynomial.
Real a() const
Returns the left boundary of the interval containing all real roots.
Definition Utils_Poly.hh:1128
Eigen::Matrix< Real, Eigen::Dynamic, 1 > dvec_t
Definition Utils_Poly.hh:909
Real b() const
Returns the right boundary of the interval containing all real roots.
Definition Utils_Poly.hh:1138
Sturm()
Definition Utils_Poly.hh:942
void refine_roots()
Refine the roots of the polynomial after the intervals have been separated.
int Integer
Definition Utils_Poly.hh:907
Definition SystemUtils.cc:39
Quaternion< T > operator*(Quaternion< T > const &a, Quaternion< T > const &b)
Definition Quaternion.hxx:298
ostream_type & operator<<(ostream_type &os, Quaternion< T > const &Q)
Definition Quaternion.hxx:314