Program Listing for File Utils_Poly.hh¶
↰ Return to documentation for file (Utils_Poly.hh)
/*--------------------------------------------------------------------------*\
| |
| Copyright (C) 2022 |
| |
| , __ , __ |
| /|/ \ /|/ \ |
| | __/ _ ,_ | __/ _ ,_ |
| | \|/ / | | | | \|/ / | | | |
| |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
| /| /| |
| \| \| |
| |
| Enrico Bertolazzi |
| Dipartimento di Ingegneria Industriale |
| Universita` degli Studi di Trento |
| email: enrico.bertolazzi@unitn.it |
| |
\*--------------------------------------------------------------------------*/
#pragma once
#ifndef UTILS_POLY_dot_HH
#define UTILS_POLY_dot_HH
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include "Utils.hh"
#include "Eigen/Dense"
namespace Utils {
template <typename Real>
class Poly : public Eigen::Matrix<Real,Eigen::Dynamic,1> {
public:
typedef int Integer;
typedef Eigen::Matrix<Real,Eigen::Dynamic,1> dvec_t;
typedef Poly<Real> Poly_t;
private:
Integer m_order;
dvec_t & to_eigen() { return *static_cast<dvec_t*>(this); }
public:
Poly() : m_order(0) {}
Poly( int order ) : m_order(order) {
this->resize(order);
this->setZero();
}
Poly( Poly_t const & c )
{ *this = c; }
Poly( dvec_t const & c ) {
this->resize( c.size() );
// per evitare la ricorsione devo chiamare esplicitamente
// l'operatore = della classe di base.
this->dvec_t::operator = (c);
m_order = c.size();
}
// accesso to the Eigen class
dvec_t const &
to_eigen() const
{ return * static_cast<dvec_t const *>(this); }
void
set_order( Integer order ) {
m_order = order;
this->resize( order );
this->setZero();
}
void
set_degree( Integer degree ) {
m_order = degree+1;
this->resize( m_order );
this->setZero();
}
Poly_t & set_scalar( Real a );
Poly_t & set_monomial( Real a );
dvec_t coeffs() const { return to_eigen(); }
Integer degree() const { return m_order-1; }
Integer order() const { return m_order; }
// stampa il polinomio
//friend std::basic_ostream & operator<<( std::ostream&, Poly_t const & );
Real eval( Real x ) const;
Real eval_D( Real x ) const;
void eval( Real x, Real & p, Real & Dp ) const;
Real leading_coeff() const { return this->coeff(m_order-1); }
void derivative( Poly_t & ) const;
void integral( Poly_t & ) const;
Real normalize( void );
void purge( Real epsi );
void adjust_degree( void );
Integer sign_variations( void ) const;
void
make_monic( void ) {
this->to_eigen() /= this->coeff(m_order-1);
this->coeffRef(m_order-1) = 1;
}
Poly_t & operator = ( Poly_t const & );
Poly_t operator-() { return Poly(-this->to_eigen()); }
Poly_t & operator += ( Poly_t const & ); // somma al polinomio
Poly_t & operator -= ( Poly_t const & ); // sottrai al polinomio
Poly_t & operator *= ( Poly_t const & ); // moltiplica il polinomio
Poly_t & operator += ( Real ); // somma al polinomio
Poly_t & operator -= ( Real ); // sottrai al polinomio
Poly_t & operator *= ( Real ); // moltiplica il polinomio
};
template <typename Real>
class Sturm {
public:
typedef int Integer;
typedef Poly<Real> Poly_t;
typedef Eigen::Matrix<Real,Eigen::Dynamic,1> dvec_t;
typedef struct {
Real a;
Real b;
Real va;
Real vb;
} Interval;
private:
std::vector<Poly_t> m_sturm;
std::vector<Interval> m_intervals;
Real m_a, m_b;
dvec_t m_roots;
Integer m_max_iter;
public:
Sturm() : m_a(0), m_b(0), m_max_iter(20) {}
void build( Poly_t const & p );
Integer length() const { return Integer(m_sturm.size()); }
Poly_t const & get( Integer i ) const { return m_sturm[i]; }
Integer sign_variations( Real x, bool & on_root ) const;
Integer separate_roots( Real a, Real b );
Integer n_roots() const { return Integer(m_intervals.size()); }
Real a() const { return m_a; }
Real b() const { return m_b; }
Interval const & get_interval( Integer i ) const { return m_intervals[i]; }
void refine_roots( Real tol );
dvec_t const & roots() const { return m_roots; }
};
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
Poly<Real> operator + ( Poly<Real> const & a, Poly<Real> const & b );
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
Poly<Real> operator + ( Poly<Real> const & a, Real b );
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
Poly<Real> operator + ( Real a, Poly<Real> const & b );
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
Poly<Real> operator - ( Poly<Real> const & a, Poly<Real> const & b );
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
Poly<Real> operator - ( Poly<Real> const & a, Real b );
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
Poly<Real> operator - ( Real a, Poly<Real> const & b );
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
Poly<Real> operator * ( Poly<Real> const & a, Poly<Real> const & b );
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
Poly<Real> operator * ( Real a, Poly<Real> const & b );
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
Poly<Real> operator * ( Poly<Real> const & a, Real b );
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
void divide(
Poly<Real> const & p,
Poly<Real> const & q,
Poly<Real> & M,
Poly<Real> & R
);
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real>
void
GCD(
Poly<Real> const & p,
Poly<Real> const & q,
Poly<Real> & g
);
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real, typename Char>
inline
std::basic_ostream<Char> &
operator << ( std::basic_ostream<Char> & output, Poly<Real> const & p ) {
bool empty = true; // true indica che i coefficienti finora sono nulli
std::string s = ""; // segno
Real c = 0; // coefficiente
std::string e = ""; // esponente
if ( p.order() <= 0 ) { output << "EMPTY!"; return output; }
if ( p.order() == 1 ) { output << p(0); return output; }
if ( p.cwiseAbs().maxCoeff() == 0 ) { output << 0; return output; }
// controlla se esiste il primo coefficiente (grado 0)
if ( p.coeff(0) != 0 ) {
output << p.coeff(0);
empty = false;
}
for ( typename Poly<Real>::Integer i=1; i < p.order(); ++i ) {
// se il coefficiente e` negativo...
if ( p.coeff(i) < 0 ) {
// e se i coefficienti precenti erano nulli...
if ( empty ) {
s = ""; // ...non scrive il segno
c = p.coeff(i);
empty = false;
} else {
s = " - "; // ...altrimenti scrive il segno come separatore
c = -p.coeff(i); // e inverte il segno del coefficiente
}
// se il coefficiente e` positivo...
} else if ( p.coeff(i) > 0 ) {
c = p.coeff(i);
// e se i coefficienti precenti erano nulli...
if ( empty ) {
s = ""; // ...non scrive il segno
empty = false;
} else {
s = " + "; // ...altrimenti scrive il segno come separatore
}
// se il coefficiente e` zero...
} else {
continue; // ...procede al prossimo
}
// se il grado e` 1 non scrive l'esponente
if ( i == 1 ) e = "x";
else e = fmt::format( "x^{}", i );
// se il coeff è 1 non lo stampo
if ( c == 1 ) output << s << e; // stampa
else output << s << c << ' ' << e; // stampa
}
return output;
}
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
template <typename Real, typename Char>
inline
std::basic_ostream<Char> &
operator << ( std::basic_ostream<Char> & output, Sturm<Real> const & S ) {
typedef typename Poly<Real>::Integer Integer;
fmt::print( output, "Sturm sequence\n" );
for ( Integer i = 0; i < S.length(); ++i )
fmt::print( output, "P_{}(x) = {}\n", i, S.get(i) );
Integer n = S.n_roots();
if ( n > 0 ) {
fmt::print( output, "roots separation for interval [{},{}]\n", S.a(), S.b() );
for ( Integer i = 0; i < n; ++i ) {
typename Sturm<Real>::Interval const & I = S.get_interval( i );
fmt::print( output, "I = [{}, {}], V = [{}, {}]\n", I.a, I.b, I.va, I.vb );
}
}
return output;
}
/*
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#ifndef UTILS_OS_WINDOWS
extern template class Poly<float>;
extern template class Sturm<float>;
extern template class Poly<double>;
extern template class Sturm<double>;
#endif
}
#endif