#ifndef _POLYNOMIAL_HPP #define _POLYNOMIAL_HPP #include #include // std::complex #include #include #include #define MIN(a,b) (((a) < (b))? (a) : (b)) #define MAX(a,b) (((a) > (b))? (a) : (b)) class _Polynomial { public: _Polynomial() {} ~_Polynomial() {} static unsigned int *combinatorial; static void startCombinatorialNumbers (int degree); static void releaseCombinatorialNumbers () { delete [] _Polynomial::combinatorial; } }; template class Polynomial : _Polynomial { public: // CONSTRUCTOR Polynomial (int = 0); Polynomial (int, const T *); Polynomial (const Polynomial &); ~Polynomial () {delete [] coef;} // ASSIGNMENT Polynomial & operator= (const Polynomial &); Polynomial & operator= (const T &); Polynomial & operator= (double); T operator() (const T &, const T &) const; T diffX (const T &, const T &) const; T diffY (const T &, const T &) const; T diffXX (const T &, const T &) const; T diffXY (const T &, const T &) const; T diffYY (const T &, const T &) const; // MISC FUNCTIONS FOR HORNER T evalPolClassic (const T &, const T &) const; T evalIPolHornerXY (const T &, const T &) const {return T();} T evalIPolHornerYX (const T &, const T &) const {return T();} T evalPolYClassic (const T &, const T &) const; T evalIPolYHornerXY (const T &, const T &) const {return T();} T evalIPolYHornerYX (const T &, const T &) const {return T();} // CHANGE OF VARIABLE Polynomial IlinearVarChange (const T &a) const; Polynomial IlinearVarChange2 (const T &x0) const; // MEMBERS T *coef; int degree; }; template std::ostream & operator<< (std::ostream &output, const Polynomial &op) { int allZero = 1; for (int i=0; i<=op.degree; ++i) for (int j=0; j<=i; ++j){ if (op.coef[i*(i+1)/2 + j] == 0.0) continue; allZero = 0; if (op.coef[i*(i+1)/2 + j] == -1.0) output << "-"; else if (op.coef[i*(i+1)/2 + j] != 1.0) output << "+(" << op.coef[i*(i+1)/2 + j] << ")*"; else output << "+"; if (i == 0) if (op.coef[0] == T(1)) output << "1"; if (i != 0) if (i-j == 0) if (j == 1) output << "y"; else output << "y^" << j; else if (i-j == 1) if (j == 0) output << "x"; else if (j == 1) output << "x*y"; else output << "x*y^" << j; else if (j == 0) output << "x^" << i; else if (j == 1) output << "x^" << (i-j) << "*y"; else output << "x^" << (i-j) << "*y^" << j; } if (allZero) output << "0"; return output; } // CONSTRUCTOR // DEFAULT CONSTRUCTOR FOR ZERO POLYNOMIAL template Polynomial::Polynomial (int op) { degree = op; coef = new T [((op+1)*(op+2))/2]; for (int i=0; i<((op+1)*(op+2))/2; ++i) coef[i] = 0.0; } // CONSTRUCTOR FROM ARRAY OF COMPLEX or ICOMPLEX template Polynomial::Polynomial (int op1, const T *op2) { degree = op1; int nCoef = ((degree+1)*(degree+2)) / 2; coef = new T [nCoef]; for (int i=0; i Polynomial::Polynomial (const Polynomial &op) { degree = op.degree; int nCoef = ((degree+1)*(degree+2)) / 2; coef = new T [nCoef]; for (int i=0; i Polynomial & Polynomial::operator= (const Polynomial &op) { // CHECKS WHETHER ASSIGNED POL IS TARGET POL if (this == &op) return (*this); // GETS FINAL NUMBER OF COEFICIENTS int nCoef = ((op.degree+1)*(op.degree+2)) / 2; // IF NUMBER OF COEFFICIENTS ARE THE SAME, NO NEED TO REALLOCATE if (this->degree != op.degree) { delete [] this->coef; this->coef = new T[nCoef]; this->degree = op.degree; } // UPDATE VALUES OF COEFICIENTS for (int i=0; icoef[i] = op.coef[i]; return (*this); } template Polynomial & Polynomial::operator= (const T &op) { // CHECKS IF TARGET POL IS ALSO A CONSTANT POL // IN THAT CASE THERE IS NO NEED TO REALLOCATE MEMORY if (this->degree != 0) { delete [] this->coef; this->coef = new T[1]; this->degree = 0; } // UPDATE INDEPENDENT TERM this->coef[0] = op; return (*this); } template Polynomial & Polynomial::operator= (double op) { // USE PREVIOUS DEFINITION return ((*this) = T(op)); } // EVALUATION template T Polynomial::evalPolClassic (const T &x, const T &y) const { // coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i', // with degree of second variable 'j' -> coef of x^(i-j) y^j // i; // counter along degree of polynomial // j; // counter for monomials of equal degree // sets output to 0+0i T rop; // compute all powers of x and y (from 0 to degree) T xPower[this->degree+1], yPower[this->degree+1]; xPower[0] = yPower[0] = 1.0; xPower[1] = x; yPower[1] = y; for (int j=1; jdegree; ++j) { xPower[j+1] = xPower[j] * x; yPower[j+1] = yPower[j] * y; } // loop for each monomial of each degree for (int i=0; i<=this->degree; ++i) for (int j=0; j<=i; ++j) rop = rop + ((this->coef)[(i*(i+1))/2 + j]) * xPower[i-j] * yPower[j]; return rop; } template T Polynomial::operator() (const T &x, const T &y) const { return this->evalPolClassic (x,y); } template T Polynomial::diffX (const T &x, const T &y) const { // coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i', // with degree of second variable 'j' -> coef of x^(i-j) y^j // i; // counter along degree of polynomial // j; // counter for monomials of equal degree // sets output to 0+0i T rop; // compute all powers of x and y // (from 0 to degree-1) (from 0 to degree) resp T xPower[this->degree], yPower[this->degree+1]; xPower[0] = yPower[0] = 1.0; xPower[1] = x; yPower[1] = y; for (int j=1; jdegree-1; ++j) { xPower[j+1] = xPower[j] * x; yPower[j+1] = yPower[j] * y; } yPower[this->degree] = yPower[this->degree-1] * y; // loop for each monomial of each degree for (int i=1; i<=this->degree; ++i) for (int j=0; jcoef)[(i*(i+1))/2 + j]) * xPower[i-j-1] * yPower[j]; return rop; } template T Polynomial::evalPolYClassic (const T &x, const T &y) const { // coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i', // with degree of second variable 'j' -> coef of x^(i-j) y^j // i; // counter along degree of polynomial // j; // counter for monomials of equal degree // sets output to 0+0i T rop; // compute all powers of x and y // (from 0 to degree) (from 0 to degree-1) resp T xPower[this->degree], yPower[this->degree]; xPower[0] = yPower[0] = 1.0; xPower[1] = x; yPower[1] = y; for (int j=1; jdegree-1; ++j) { xPower[j+1] = xPower[j] * x; yPower[j+1] = yPower[j] * y; } // loop for each monomial of each degree for (int i=1; i<=this->degree; ++i) for (int j=1; j<=i; ++j) rop = rop + T(j)*((this->coef)[(i*(i+1))/2 + j]) * xPower[i-j] * yPower[j-1]; return rop; } template T Polynomial::diffY (const T &x, const T &y) const { return this->evalPolYClassic (x,y); } template T Polynomial::diffXX (const T &x, const T &y) const { // coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i', // with degree of second variable 'j' -> coef of x^(i-j) y^j // i; // counter along degree of polynomial // j; // counter for monomials of equal degree // sets output to 0+0i T rop; // compute all powers of x and y // (from 0 to degree-2) (from 0 to degree-2) resp T xPower[this->degree-1], yPower[this->degree-1]; xPower[0] = yPower[0] = 1.0; xPower[1] = x; yPower[1] = y; for (int j=1; jdegree-2; ++j) { xPower[j+1] = xPower[j] * x; yPower[j+1] = yPower[j] * y; } // loop for each monomial of each degree for (int i=2; i<=this->degree; ++i) for (int j=0; jcoef)[(i*(i+1))/2 + j]) * xPower[i-j-2] * yPower[j]; return rop; } template T Polynomial::diffXY (const T &x, const T &y) const { // coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i', // with degree of second variable 'j' -> coef of x^(i-j) y^j // i; // counter along degree of polynomial // j; // counter for monomials of equal degree // sets output to 0+0i T rop; // compute all powers of x and y // (from 0 to degree-2) (from 0 to degree-2) resp T xPower[this->degree-1], yPower[this->degree-1]; xPower[0] = yPower[0] = 1.0; xPower[1] = x; yPower[1] = y; for (int j=1; jdegree-2; ++j) { xPower[j+1] = xPower[j] * x; yPower[j+1] = yPower[j] * y; } // loop for each monomial of each degree for (int i=2; i<=this->degree; ++i) for (int j=1; jcoef)[(i*(i+1))/2 + j]) * xPower[i-j-1] * yPower[j-1]; return rop; } template T Polynomial::diffYY (const T &x, const T &y) const { // coef[(i*(i+1))/2 + j] is coeficient of monomial of degree 'i', // with degree of second variable 'j' -> coef of x^(i-j) y^j // i; // counter along degree of polynomial // j; // counter for monomials of equal degree // sets output to 0+0i T rop; // compute all powers of x and y // (from 0 to degree-2) (from 0 to degree-2) resp T xPower[this->degree-1]; T yPower[this->degree-1]; xPower[0] = yPower[0] = 1.0; xPower[1] = x; yPower[1] = y; for (int j=1; jdegree-2; ++j) { xPower[j+1] = xPower[j] * x; yPower[j+1] = yPower[j] * y; } // loop for each monomial of each degree for (int i=2; i<=this->degree; ++i) for (int j=2; j<=i; ++j) rop = rop + T(j)*T(j-1)*((this->coef)[(i*(i+1))/2 + j]) * xPower[i-j] * yPower[j-2]; return rop; } // CHANGE OF VARIABLE // RETURNS q = p(x, y + ax); // q = sum D(i,j)x^(i-j)y^j template Polynomial Polynomial::IlinearVarChange (const T &a) const { int i; // counter for degree int j; // counter for exponent of y int k; // counter for elements modifying x^(i-j) y^j // for each degree i, only coefficients of monomials with j in {0, ..., i-1} are changed // for each j, only monomials with degree i and k in {j+1, ..., i} modify it // for each k, coef[(i*(i+1))/2+k] x^(i-k) (y+ax)^k // from binomial expansion, the term with x^(i-j) y^j has multiplier: // coef[(i*(i+1))/2+k] a^(k-j) (k over j) T aPower[this->degree+1]; aPower[0] = 1; aPower[1] = a; for (i=1; idegree; ++i) aPower[i+1] = aPower[i] * a; unsigned int *combinatorial = _Polynomial::combinatorial; Polynomial rop(this->degree); // rop = sum_{i=0}^{degree} sum_{j=0}^{i} D(i,j)x^{i-j}y^j // D(i,j) = sum_{k=j}^{i} C(i,k)(k over j) a^{k-j} for (i=0; i<=this->degree; ++i) for (j=0; j<=i; ++j) { rop.coef[(i*(i+1))/2 + j] = this->coef[(i*(i+1))/2 + j]; for (k=j+1; k<=i; ++k) rop.coef[(i*(i+1))/2 + j] = rop.coef[(i*(i+1))/2 + j] + combinatorial[(k*(k+1))/2+j] * aPower[k-j] * this->coef[(i*(i+1))/2+k]; } return rop; } // RETURNS q = p(x+x0, y); template Polynomial Polynomial::IlinearVarChange2 (const T &x0) const { int i; // counter for degree int j; // counter for exponent of y int k; // counter for elements modifying x^(i-j) y^j // for each degree i, only coefficients of monomials with j in {0, ..., i-1} are changed // for each j, only monomials with degree i and k in {j+1, ..., i} modify it // for each k, coef[(i*(i+1))/2+k] x^(i-k) (y+ax)^k // from binomial expansion, the term with x^(i-j) y^j has multiplier: // coef[(i*(i+1))/2+k] a^(k-j) (k over j) T x0Power[this->degree+1]; x0Power[0] = 1; x0Power[1] = x0; for (i=1; idegree; ++i) x0Power[i+1] = x0Power[i] * x0; unsigned int *combinatorial = _Polynomial::combinatorial; Polynomial rop(this->degree); // rop = sum_{i=0}^{degree} sum_{j=0}^{i} D(i,j)x^{i-j}y^j // D(i,j) = sum_{k=i}^{degree} (k-j over i-j) C(k,j) x0^(k-i) for (i=0; i<=this->degree; ++i) for (j=0; j<=i; ++j) { rop.coef[(i*(i+1))/2+j] = this->coef[(i*(i+1))/2+j]; for (k=i+1; k<=this->degree; ++k) rop.coef[(i*(i+1))/2+j] = rop.coef[(i*(i+1))/2+j] + combinatorial[((k-j)*(k-j+1))/2 + i-j] * this->coef[(k*(k+1))/2+j] * x0Power[k-i]; } return rop; } #endif