// // $Source: /cvsroot/gambit/gambit/sources/tools/enumpoly/gpoly.imp,v $ // $Date: 2006/08/17 03:05:00 $ // $Revision: 1.7 $ // // DESCRIPTION: // Implementation of multivariate polynomial type // // This file is part of Gambit // Copyright (c) 2002, The Gambit Project // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #include "gpoly.h" #include "libgambit/libgambit.h" //--------------------------------------------------------------- // gPoly //--------------------------------------------------------------- //--------------------------- // Constructors / Destructor //--------------------------- template gPoly::gPoly(const gSpace* p, const term_order* o) : Space(p), Order(o), Terms() { } template gPoly::gPoly(const gSpace* p, const T& constant, const term_order* o) : Space(p), Order(o), Terms() { if (constant != (T)0) Terms.Append(gMono(p,constant)); } template gPoly::gPoly(const gSpace *p, const std::string &s, const term_order* o) : Space(p), Order(o), Terms() { *this=s; // Operator = needs to be fixed } template gPoly::gPoly(const gSpace *p, int var_no, int exp, const term_order* o) : Space(p), Order(o), Terms() { Terms.Append(gMono((T)1,exp_vect(p,var_no,exp))); } template gPoly::gPoly(const gSpace* p, exp_vect exps, T coeff, const term_order* o) : Space(p), Order(o), Terms() { Terms.Append(gMono(coeff,exps)); } template gPoly::gPoly(const gSpace* p, const gMono& mono, const term_order* o) : Space(p), Order(o), Terms() { Terms.Append(mono); } template gPoly::gPoly(const gPoly &p) : Space(p.Space), Order(p.Order), Terms(p.Terms) { *this=p; } template gPoly::~gPoly() { } //---------------------------------- // Operators //---------------------------------- template gPoly &gPoly::operator=(const gPoly &p) { assert (Space == p.Space && Order == p.Order); Terms = p.Terms; return (*this); } template gPoly& gPoly::operator=(const std::string &Hold) { Gambit::List > nullTerms; Terms = nullTerms; // get rid of old Terms charnum = 0; int contflag = 1; T nega = 1; Gambit::Array PowArray(Space->Dmnsn()); TheString = Hold + " +"; charc = TheString[charnum]; while (charnum <= TheString.length() && contflag){ switch (charc) { case '+' : case ' ': charnum++; charc = TheString[charnum]; break; case '-': charnum++; charc = TheString[charnum]; nega = -nega; break; case 0: //Null termination of string contflag = 0; break; default: String_Term(nega); nega = T (1); break; } } Gambit::List > newTerms; for (int j = 1; j <= Terms.Length(); j++) { int low = 0; int high = newTerms.Length() + 1; while (low +1 < high) { int test = low + (high - low)/2; if (1 <= test && test <= newTerms.Length()) assert (Terms[j].ExpV() != newTerms[test].ExpV()); if ( Order->Less(Terms[j].ExpV(),newTerms[test].ExpV()) ) high = test; else low = test; } newTerms.Insert(Terms[j],high); } Terms = newTerms; return (*this); } template gPoly gPoly::operator-() const { gPoly neg(*this); for (int j = 1; j <= Terms.Length(); j++) neg.Terms[j] = -Terms[j]; return neg; } template gPoly gPoly::operator-(const gPoly &p) const { gPoly dif(*this); dif -= p; return dif; } template void gPoly::operator-=(const gPoly &p) { assert(Space == p.Space); gPoly neg = p; for (int i = 1; i <= neg.Terms.Length(); i++) neg.Terms[i] = - neg.Terms[i]; Terms = Adder(Terms,neg.Terms); } template gPoly gPoly::operator+(const gPoly &p) const { gPoly sum(*this); sum += p; return sum; } template void gPoly::operator+=(const gPoly &p) { assert(Space == p.Space); Terms = Adder(Terms,p.Terms); } template void gPoly::operator+=(const T& val) { *this += gPoly(Space,val,Order); } template gPoly gPoly::operator*(const gPoly &p) const { gPoly prod(*this); prod *= p; return prod; } template gPoly gPoly::operator/(const T val) const { assert (val != (T)0); T one = (T)1; return (one/val) * (*this); } template gPoly gPoly::operator/(const gPoly & den) const { return DivideByPolynomial(den); } template void gPoly::operator*=(const gPoly &p) { assert(Space == p.Space); Terms = Mult(Terms,p.Terms); } template void gPoly::operator*=(const T& val) { for (int j = 1; j <= Terms.Length(); j++) Terms[j] *= val; } template bool gPoly::operator==(const gPoly &p) const { assert(Space == p.Space && Order == p.Order); if (Terms.Length() != p.Terms.Length()) return false; if (Terms.Length() == 0 && p.Terms.Length() == 0) return true; return (Terms == p.Terms); } template bool gPoly::operator!=(const gPoly &p) const { return !(*this == p); } //---------------------------------- // Member Functions //---------------------------------- template void gPoly::String_Term(T nega) { Gambit::Array PowArray(Dmnsn()); for (int a=1; a<= Dmnsn(); a++) PowArray[a] = 0; T val; val = String_Coeff(nega); while (charc != '+' && charc != '-') { if (charc == ' ') { charnum++; charc = TheString[charnum]; } else String_VarAndPow(PowArray); } Terms.Append(gMono(val, exp_vect(Space,PowArray))); } template int gPoly::String_GetPow(void) { std::string Pow = ""; while (charc == ' '){ charnum++; charc = TheString[charnum]; } while (charc >= '0' && charc <= '9'){ Pow += charc; charnum++; charc = TheString[charnum]; } return (atoi(Pow.c_str())); } template void gPoly::String_VarAndPow(Gambit::Array &PowArray) { std::string VarName = ""; int pow, varname; while (charc != '^' && charc != ' '){ VarName += charc; charnum++; charc = TheString[charnum]; } if (charc == '^') { charnum++; charc = TheString[charnum]; pow = String_GetPow(); } else pow = 1; for(varname = 1;varname <= Dmnsn() && VarName != (Space->VariableWithNumber(varname))->Name; varname ++); if (varname <= Dmnsn()) PowArray[varname] = pow; } // bool function to check the string in &Hold template bool gPoly::Check_String(const std::string &Hold){ unsigned int charnum=0; int boolflag=0; // state variables int statenumber=0; int statevar=0; int statesign=1; //values of the state variables enum number {nonumberbef, numberbef}; enum var {novarbef, varbef}; enum sign {nosignbef, signbef}; std::string TheString = Hold; char charc = TheString[charnum]; //movement along the string with a switch case while (charnum < TheString.length()){ switch (charc){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': statenumber=numberbef; statesign=nosignbef; break; case 'n': if (statenumber==0 && statesign==0) boolflag++; if (charnum == (TheString.length()-1)) boolflag++; statenumber=number(0); statevar=varbef; statesign=nosignbef; break; case '^': if (statenumber==0) boolflag++; if (statevar==0) boolflag++; if (charnum == (TheString.length()-1)) boolflag++; statenumber=nonumberbef; statevar=novarbef; statesign=nosignbef; break; case '/': case '.': if (statenumber==0) boolflag++; if (charnum == (TheString.length()-1)) boolflag++; statenumber=nonumberbef; statesign=nosignbef; break; case '+': case '-': if (statenumber==0 && charnum!=0) boolflag++; if (charnum == (TheString.length()-1)) boolflag++; statenumber=nonumberbef; statevar=novarbef; statesign=signbef; break; case ' ': break; default: boolflag++; break; } charnum++; charc = TheString[charnum]; } // return values if (boolflag==0) return true; else return false; } template void gPoly::GetChar(void) { charc = TheString[charnum]; } //---------------------------------- // Information //---------------------------------- template const gSpace* gPoly::GetSpace(void) const { return (gSpace *) Space; } template const term_order* gPoly::GetOrder(void) const { return (term_order *) Order; } template int gPoly::Dmnsn() const { return Space->Dmnsn(); } template int gPoly::DegreeOfVar(int var_no) const { int max = 0; for (int j = 1; j <= Terms.Length(); j++) if (max < Terms[j].ExpV()[var_no]) max = Terms[j].ExpV()[var_no]; return max; } template bool gPoly::IsZero() const { if (Terms.Length() == 0) return true; else return false; } template int gPoly::Degree() const { int max = 0; for (int j = 1; j <= Terms.Length(); j++) if (Terms[j].TotalDegree() > max) max = Terms[j].TotalDegree(); return max; } template T gPoly::GetCoef(const Gambit::Array &Powers) const { return GetCoef(exp_vect(Space,Powers)); } template T gPoly::GetCoef(const exp_vect &Powers) const { for (int j = 1; j <= Terms.Length(); j++) if (Terms[j].ExpV() == Powers) return Terms[j].Coef(); return (T)0; } template T gPoly::NumLeadCoeff() const { assert (Degree() == 0 && Terms.Length() <= 1); if (Terms.Length() == 1) return Terms[1].Coef(); else return (T)0; } template bool gPoly::IsConstant() const { for (int i = 1; i <= Terms.Length(); i++) if (!Terms[i].IsConstant()) return false; return true; } template bool gPoly::IsMultiaffine() const { for (int i = 1; i <= Terms.Length(); i++) if (!Terms[i].IsMultiaffine()) return false; return true; } template T gPoly::Evaluate(const Gambit::Array &values) const { T answer=0; for (int j = 1; j <= Terms.Length(); j++) answer += Terms[j].Evaluate(values); return answer; } template Gambit::List gPoly::ExponentVectors() const { Gambit::List result; for (int j = 1; j <= Terms.Length(); j++) result.Append(exp_vect(Terms[j].ExpV())); return result; } template Gambit::List > gPoly::MonomialList() const { return Terms; } template int gPoly::No_Monomials() const { // gout << "Eliminate old code in No_monomials, if successful.\n"; return Terms.Length(); } template int gPoly::UniqueActiveVariable() const { Gambit::List ExpVecs = ExponentVectors(); int activar = 0; for (int i = 1; i <= ExpVecs.Length(); i++) { for (int j = 1; j <= Dmnsn(); j++) { if (ExpVecs[i][j] > 0) if (activar > 0 && activar != j) return -1;// multivariate! else activar = j; } } return activar; } template polynomial gPoly::UnivariateEquivalent(int activar) const { assert(UniqueActiveVariable() >= 0); Gambit::List coefs; if (!IsZero()) { for (int h = 0; h <= DegreeOfVar(activar); h++) coefs.Append((T)0); for (int i = 1; i <= Terms.Length(); i++) coefs[Terms[i].ExpV()[activar] + 1] = Terms[i].Coef(); } return polynomial(coefs); } //------------------------------------------------------------- // Private Versions of Arithmetic Operators //------------------------------------------------------------- template Gambit::List< gMono > gPoly::Adder(const Gambit::List >& One, const Gambit::List >& Two) const { if (One.Length() == 0) return Two; if (Two.Length() == 0) return One; Gambit::List > answer; int i = 1; int j = 1; while (i <= One.Length() || j <= Two.Length()) { if (i > One.Length()) { answer.Append(Two[j]); j++; } else if (j > Two.Length()) { answer.Append(One[i]); i++; } else { if ( Order->Less( One[i].ExpV(),Two[j].ExpV()) ) { answer.Append(One[i]); i++; } else if ( Order->Greater(One[i].ExpV(),Two[j].ExpV()) ) { answer.Append(Two[j]); j++; } else { if (One[i].Coef() + Two[j].Coef() != (T)0) answer.Append(One[i] + Two[j]); i++; j++; } } } return answer; } template Gambit::List< gMono > gPoly::Mult(const Gambit::List >& One, const Gambit::List >& Two) const { Gambit::List > answer; if (One.Length() == 0 || Two.Length() == 0) return answer; int i; for (i = 1; i <= One.Length(); i++) for (int j = 1; j <= Two.Length(); j++) { gMono next = One[i] * Two[j]; if (answer.Length() == 0) answer.Append(next); else { int bot = 1; int top = answer.Length(); if ( Order->Less (answer[top].ExpV(),next.ExpV()) ) answer.Append(next); else if ( Order->Greater(answer[bot].ExpV(),next.ExpV()) ) answer.Insert(next,1); else { if ( answer[bot].ExpV() == next.ExpV() ) top = bot; else if ( answer[top].ExpV() == next.ExpV() ) bot = top; while (bot < top - 1) { int test = bot + (top - bot)/2; if ( answer[test].ExpV() == next.ExpV() ) bot = top = test; else if (Order->Less (answer[test].ExpV(),next.ExpV())) bot = test; else // (Order->Greater(answer[test].ExpV(),next.ExpV())) top = test; } if (bot == top) answer[bot] += next; else answer.Insert(next,top); } } } return answer; } template gPoly gPoly::DivideByPolynomial(const gPoly &den) const { gPoly zero(Space,(T)0,Order); assert(den != zero); assert(*this == zero || den.Degree() <= Degree()); // assumes exact divisibility! gPoly result = zero; if (*this == zero) return result; else if (den.Degree() == 0) { result = *this/den.NumLeadCoeff(); return result; } else { int last = Dmnsn(); while (den.DegreeOfVar(last) == 0) last--; gPoly remainder = *this; while (remainder != zero) { gPoly quot = remainder.LeadingCoefficient(last) / den.LeadingCoefficient(last); gPoly power_of_last(Space,last,remainder.DegreeOfVar(last) - den.DegreeOfVar(last),Order); result += quot * power_of_last; remainder -= quot * power_of_last * den; } } return result; } template gPoly gPoly::EvaluateOneVar( int varnumber, T val) const { gPoly answer(Space,(T)0,Order); for (int i = 1; i <= Terms.Length(); i++) answer += gPoly(Space, Terms[i].ExpV().AfterZeroingOutExpOfVariable(varnumber), ((T) Terms[i].Coef())* ((T) pow(val,(long int)Terms[i].ExpV()[varnumber])), Order); return answer; } template exp_vect gPoly::OrderMaxMonomialDivisibleBy(const term_order& order, const exp_vect& /*expv*/) { // gout << "You have just tested OrderMaxMonomialDivisibleBy.\n"; exp_vect answer(Space); // constructs [0,..,0] for (int i = 1; i <= Terms.Length(); i++) if ( order.Less(answer,Terms[i].ExpV()) && answer < Terms[i].ExpV() ) answer = Terms[i].ExpV(); return answer; } template gPoly gPoly::PartialDerivative(int varnumber) const { gPoly newPoly(*this); for (int i = 1; i <= newPoly.Terms.Length(); i++) newPoly.Terms[i] = gMono(newPoly.Terms[i].Coef() * (T)newPoly.Terms[i].ExpV()[varnumber], newPoly.Terms[i].ExpV().AfterDecrementingExpOfVariable(varnumber)); int j = 1; while (j <= newPoly.Terms.Length()) { if (newPoly.Terms[j].Coef() == (T)0) newPoly.Terms.Remove(j); else j++; } return (newPoly); } template gPoly gPoly::LeadingCoefficient(int varnumber) const { gPoly newPoly(*this); int degree = DegreeOfVar(varnumber); newPoly.Terms = Gambit::List >(); for (int j = 1; j <= Terms.Length(); j++) { if (Terms[j].ExpV()[varnumber] == degree) newPoly.Terms.Append(gMono(Terms[j].Coef(), Terms[j].ExpV().AfterZeroingOutExpOfVariable(varnumber))); } return (newPoly); } //-------------------- // Term Order Concepts //-------------------- template exp_vect gPoly::LeadingPowerProduct(const term_order & order) const { assert (Terms.Length() > 0); if (*Order == order) // worth a try ... return Terms[Terms.Length()].ExpV(); else { int max = 1; for (int j = 2; j <= Terms.Length(); j++) { if ( order.Less(Terms[max].ExpV(),Terms[j].ExpV()) ) max = j; } return Terms[max].ExpV(); } } template T gPoly::LeadingCoefficient(const term_order & order) const { if (*Order == order) // worth a try ... return Terms[Terms.Length()].Coef(); else { int max = 1; for (int j = 2; j <= Terms.Length(); j++) if ( order.Less(Terms[max].ExpV(),Terms[j].ExpV()) ) max = j; return Terms[max].Coef(); } } template gPoly gPoly::LeadingTerm(const term_order & order) const { if (*Order == order) // worth a try ... return gPoly(Space,Terms[Terms.Length()],Order); else { int max = 1; for (int j = 2; j <= Terms.Length(); j++) if ( order.Less(Terms[max].ExpV(),Terms[j].ExpV()) ) max = j; return gPoly(Space,Terms[max],Order); } } template void gPoly::ToMonic(const term_order & order) { *this = *this/LeadingCoefficient(order); } template void gPoly::ReduceByDivisionAtExpV(const term_order & order, const gPoly & divisor, const exp_vect & expv) { assert(expv >= divisor.LeadingPowerProduct(order)); assert(divisor.LeadingCoefficient(order) != (T)0); gPoly factor(Space, expv - divisor.LeadingPowerProduct(order), (T)1, Order); *this -= (GetCoef(expv) / divisor.LeadingCoefficient(order)) * factor * divisor; } template void gPoly::ReduceByRepeatedDivision(const term_order & order, const gPoly & divisor) { exp_vect zero_exp_vec(Space); exp_vect exps = OrderMaxMonomialDivisibleBy(order, divisor.LeadingPowerProduct(order)); while (exps != zero_exp_vec) { ReduceByDivisionAtExpV(order, divisor, exps); exps = OrderMaxMonomialDivisibleBy(order, divisor.LeadingPowerProduct(order)); } } template gPoly gPoly::S_Polynomial(const term_order& order, const gPoly& arg2) const { exp_vect exp_lcm = (LeadingPowerProduct(order)).LCM(arg2.LeadingPowerProduct(order)); gPoly lcm = gPoly(Space,exp_lcm,(T)1,Order); gPoly L1 = lcm/LeadingTerm(order); gPoly L2 = lcm/arg2.LeadingTerm(order); return L1*(*this) - L2*arg2; } template gPoly gPoly::TranslateOfMono(const gMono& m, const Gambit::Vector& new_origin) const { gPoly answer(GetSpace(), (T)1, GetOrder()); for (int i = 1; i <= Dmnsn(); i++) { if (m.ExpV()[i] > 0) { gPoly lt(GetSpace(), i, 1, GetOrder()); lt += gPoly(GetSpace(), new_origin[i], GetOrder()); for (int j = 1; j <= m.ExpV()[i]; j++) answer *= lt; } } answer *= m.Coef(); return answer; } template gPoly gPoly::TranslateOfPoly(const Gambit::Vector& new_origin) const { gPoly answer(GetSpace(), GetOrder()); for (int i = 1; i <= this->MonomialList().Length(); i++) answer += TranslateOfMono(this->MonomialList()[i],new_origin); return answer; } template gPoly gPoly::MonoInNewCoordinates(const gMono& m, const Gambit::SquareMatrix& M) const { assert(M.NumRows() == Dmnsn()); gPoly answer(GetSpace(), (T)1, GetOrder()); for (int i = 1; i <= Dmnsn(); i++) { if (m.ExpV()[i] > 0) { gPoly linearform(GetSpace(), (T)0, GetOrder()); for (int j = 1; j <= Dmnsn(); j++) { exp_vect exps(GetSpace(), j, 1); linearform += gPoly(GetSpace(), exps, M(i,j), GetOrder()); } for (int k = 1; k <= m.ExpV()[i]; k++) answer *= linearform; } } answer *= m.Coef(); return answer; } template gPoly gPoly::PolyInNewCoordinates(const Gambit::SquareMatrix& M) const { gPoly answer(GetSpace(), GetOrder()); for (int i = 1; i <= MonomialList().Length(); i++) answer += MonoInNewCoordinates(MonomialList()[i],M); return answer; } template T gPoly::MaximalValueOfNonlinearPart(const T& radius) const { T maxcon = (T)0; for (int i = 1; i <= MonomialList().Length(); i++) if (MonomialList()[i].TotalDegree() > 1) maxcon += MonomialList()[i].Coef() * pow(radius,(long)MonomialList()[i].TotalDegree()); return maxcon; } //--------------------------- // Global Operators //--------------------------- template gPoly operator*(const T val, const gPoly &poly) { gPoly prod(poly); prod *= val; return prod; } template gPoly operator*(const gPoly &poly, const T val) { return val * poly; } template gPoly operator+(const T val, const gPoly &poly) { gPoly prod(poly); prod += val; return prod; } template gPoly operator+(const gPoly &poly, const T val) { return val + poly; } template void gPoly::Output(std::string &t) const { std::string s; if (Terms.Length() == 0) { s += "0"; } else { for (int j = 1; j <= Terms.Length(); j++) { if (Terms[j].Coef() < (T)0) { s += "-"; if (j > 1) s += " "; } else if (j > 1) s += "+ "; if ((Terms[j].Coef() != (T)1 && -Terms[j].Coef() != (T)1) || Terms[j].IsConstant() ) if (Terms[j].Coef() < (T)0) { s += Gambit::ToText(-Terms[j].Coef()); } else { s += Gambit::ToText( Terms[j].Coef()); } for (int k = 1; k <= Space->Dmnsn(); k++) { int exp = Terms[j].ExpV() [k]; if (exp > 0) { s += " "; s += (*Space)[k]->Name; if (exp != 1) { s += '^'; s += Gambit::ToText(exp); } } } if (j < Terms.Length()) s += " "; } } if (s == "") s = " 0"; t += s; } template std::string &operator<<(std::string &p_text, const gPoly &p_poly) { p_poly.Output(p_text); return p_text; } //---------------------------------- // Conversion //---------------------------------- template gPoly TogDouble(const gPoly& given) { gPoly answer(given.GetSpace(),given.GetOrder()); Gambit::List > list = given.MonomialList(); for (int i =1; i <= list.Length(); i++) { double nextcoef = (double)list[i].Coef(); gPoly next(given.GetSpace(), list[i].ExpV(), nextcoef, given.GetOrder()); answer += next; } return answer; } template gPoly NormalizationOfPoly(const gPoly& given) { Gambit::List > list = given.MonomialList(); double maxcoeff = 0.0; for (int i =1; i <= list.Length(); i++) { maxcoeff = Gambit::max(maxcoeff, (double) Gambit::abs((double) list[i].Coef())); } if (maxcoeff < 0.000000001) return TogDouble(given); gPoly answer(given.GetSpace(),given.GetOrder()); for (int i =1; i <= list.Length(); i++) { double nextcoef = (double)list[i].Coef()/maxcoeff; gPoly next(given.GetSpace(), list[i].ExpV(), nextcoef, given.GetOrder()); answer += next; } return answer; }