mirror of https://github.com/CGAL/cgal
1429 lines
38 KiB
C++
1429 lines
38 KiB
C++
/****************************************************************************
|
|
* Core Library Version 1.7, August 2004
|
|
* Copyright (c) 1995-2004 Exact Computation Project
|
|
* All rights reserved.
|
|
*
|
|
* This file is part of CORE (http://cs.nyu.edu/exact/core/); you may
|
|
* redistribute it under the terms of the Q Public License version 1.0.
|
|
* See the file LICENSE.QPL distributed with CORE.
|
|
*
|
|
* Licensees holding a valid commercial license may use this file in
|
|
* accordance with the commercial license agreement provided with the
|
|
* software.
|
|
*
|
|
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
*
|
|
* File: Curves.tcc
|
|
*
|
|
* Description:
|
|
* This file contains the implementations of
|
|
* functions defined by Curves.h
|
|
* It is included through Curves.h
|
|
* Please see Curves.h for more details.
|
|
*
|
|
* Author: Vikram Sharma and Chee Yap
|
|
* Date: April 12, 2004
|
|
*
|
|
* WWW URL: http://cs.nyu.edu/exact/
|
|
* Email: exact@cs.nyu.edu
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
***************************************************************************/
|
|
|
|
|
|
//CONSTRUCTORS FOR THE BIPOLY CLASS
|
|
////////////////////////////////////////////////////////
|
|
//Constructors
|
|
////////////////////////////////////////////////////////
|
|
|
|
template <class NT>
|
|
BiPoly<NT>::BiPoly(){ // zero polynomial
|
|
ydeg = -1;
|
|
}
|
|
|
|
//BiPoly(n)
|
|
|
|
template <class NT>
|
|
BiPoly<NT>::BiPoly(int n){// creates a BiPoly with nominal y-degree equal to n.
|
|
|
|
// To support this constructor, you need functions
|
|
// that are equivalent to "setCoeff(i, PolyNT q)" in the Poly Class
|
|
// You also want "getCoeff(i)" functions.
|
|
// E.g. BiPoly<NT> p(10);
|
|
// PolyNT q(3, {1,2,3,4});
|
|
// p.setCoeff(10, q);
|
|
// p.setCoeff(0, PolyNT());
|
|
//
|
|
ydeg = n;
|
|
if (n<0) return; // coeffX not needed
|
|
for(int i=0; i<= ydeg; i++){
|
|
Polynomial<NT> temp;
|
|
coeffX.push_back(temp);
|
|
}
|
|
}
|
|
|
|
//BiPoly(vp)
|
|
template <class NT>
|
|
BiPoly<NT>::BiPoly(std::vector<Polynomial<NT> > vp){
|
|
// From vector of Polynomials
|
|
ydeg = vp.size() - 1;
|
|
if(ydeg >=0){
|
|
coeffX = vp;
|
|
}
|
|
}
|
|
|
|
//BiPoly(p, flag):
|
|
// if true, it converts polynomial p(X) into P(Y)
|
|
// if false, it creates the polynomial Y-p(X)
|
|
|
|
template <class NT>
|
|
BiPoly<NT>::BiPoly(Polynomial<NT> p, bool flag){
|
|
if (flag){
|
|
ydeg = p.getTrueDegree();
|
|
if(ydeg >=0){
|
|
for(int i=0; i<=ydeg; i++){
|
|
Polynomial<NT> temp(0);
|
|
temp.setCoeff(0, p.getCoeffi(i));
|
|
coeffX.push_back(temp); // does STL make a copy of temp?
|
|
}//for
|
|
}//if
|
|
} else {
|
|
ydeg = 1;
|
|
coeffX.push_back(p);
|
|
coeffX.push_back(Polynomial<NT>::polyUnity());
|
|
}//else
|
|
}//BiPoly(p)
|
|
|
|
|
|
//BiPoly(deg, d[], C[]):
|
|
// Takes in a list of list of coefficients.
|
|
// Each cofficient list represents a polynomial in X
|
|
//
|
|
// deg - ydeg of the bipoly
|
|
// d[] - array containing the degrees of each coefficient (i.e., X poly)
|
|
// C[] - list of coefficients, we use array d to select the
|
|
// coefficients
|
|
|
|
template <class NT>
|
|
BiPoly<NT>::BiPoly(int deg, int *d, NT *C){
|
|
|
|
ydeg = deg;
|
|
Polynomial<NT> temp;
|
|
int max=0;
|
|
for(int i=0; i <=deg; i++)
|
|
max = core_max(d[i],max);
|
|
|
|
NT *c = new NT[max];
|
|
|
|
for(int i=0; i<= deg; i++){
|
|
for(int j=0; j <=d[i]; j++)
|
|
c[j] = C[i+j];
|
|
temp = Polynomial<NT>(d[i],c);
|
|
coeffX.push_back(temp);
|
|
}
|
|
delete[] c;
|
|
}//BiPoly(deg,d[],C[])
|
|
|
|
|
|
//The BNF syntax is the following:-
|
|
// [bipoly] -> [term]| [term] +/- [bipoly]
|
|
// [term] -> [basic term]|[basic term] [term]|[basic term]*[term]
|
|
// [basic term] -> [number]|'x'|'y'|[basic term]'^'[number]
|
|
// | '(' [bipoly]')'|'-'
|
|
//Unary minus is treated as a basic term
|
|
template <class NT>
|
|
BiPoly<NT>::BiPoly(const char * s, char myX, char myY){
|
|
string ss(s);
|
|
constructFromString(ss, myX, myY);
|
|
}
|
|
template <class NT>
|
|
BiPoly<NT>::BiPoly(const string & s, char myX, char myY){
|
|
string ss(s);
|
|
constructFromString(ss, myX, myY);
|
|
}
|
|
template <class NT>
|
|
void BiPoly<NT>::constructFromString(string & s, char myX, char myY){
|
|
if((myX != 'x' || myX != 'X') && (myY != 'y' || myY != 'Y')){
|
|
//Replace myX with 'x' and myY with 'y' in s.
|
|
unsigned int loc = s.find(myX, 0);
|
|
while(loc != string::npos){
|
|
s.replace(loc,1,1,'x');
|
|
loc = s.find(myX, loc+1);
|
|
}
|
|
loc = s.find(myY, 0);
|
|
while(loc != string::npos){
|
|
s.replace(loc,1,1,'y');
|
|
loc = s.find(myY, loc+1);
|
|
}
|
|
}
|
|
(*this) = (*this).getbipoly(s);
|
|
|
|
}
|
|
|
|
//Constructor from another BiPoly
|
|
template <class NT>
|
|
BiPoly<NT>::BiPoly(const BiPoly<NT> &P) : ydeg(P.ydeg), coeffX(P.coeffX) {
|
|
}
|
|
|
|
//Destructor
|
|
template <class NT>
|
|
void BiPoly<NT>::deleteCoeffX(){
|
|
coeffX.clear();
|
|
}
|
|
|
|
template <class NT>
|
|
BiPoly<NT>::~BiPoly(){
|
|
if (ydeg >= 0)
|
|
deleteCoeffX();
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
// METHODS USED BY STRING CONSTRUCTOR ABOVE
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
|
//Sets the input BiPoly to X^n
|
|
template <class NT>
|
|
void BiPoly<NT>::constructX(int n, BiPoly<NT>& P){
|
|
assert(n>= -1);
|
|
P.deleteCoeffX();//Clear the present coeffecients
|
|
Polynomial<NT> q(n);//Nominal degree n
|
|
q.setCoeff(n,NT(1));
|
|
if (n>0) q.setCoeff(0,NT(0));
|
|
P.coeffX.push_back(q);
|
|
P.ydeg = 0;
|
|
}
|
|
|
|
//Sets the input BiPoly to Y^n
|
|
template <class NT>
|
|
void BiPoly<NT>::constructY(int n, BiPoly<NT>& P){
|
|
P.ydeg = 0;
|
|
P.deleteCoeffX();//Clear the present coeffecients
|
|
NT cs[] = {1};
|
|
Polynomial<NT> q(0, cs);
|
|
P.coeffX.push_back(q);//P is the unit bipoly. Now we just multiply Y^n
|
|
P.mulYpower(n);
|
|
}
|
|
|
|
//Returns in P the coeffecient starting from start
|
|
template <class NT>
|
|
int BiPoly<NT>::getnumber(const char* c, int start, unsigned int len,
|
|
BiPoly<NT> & P){
|
|
int j=0;
|
|
char *temp = new char[len];
|
|
while(isint(c[j+start])){
|
|
temp[j]=c[j+start];j++;
|
|
}
|
|
temp[j] = '\0';
|
|
NT cf = NT(temp);
|
|
P.deleteCoeffX();
|
|
Polynomial<NT> q(0);
|
|
q.setCoeff(0, cf);
|
|
P.coeffX.push_back(q);
|
|
P.ydeg = 0;
|
|
delete[] temp;
|
|
|
|
return (j-1+start);//Exactly the length of the number
|
|
}
|
|
|
|
template <class NT>
|
|
bool BiPoly<NT>::isint(char c){
|
|
if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' ||
|
|
c == '5' || c == '6' || c == '7' || c == '8' || c == '9')
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
//Returns as integer the number starting from start in c
|
|
template <class NT>
|
|
int BiPoly<NT>::getint(const char* c, int start, unsigned int len,
|
|
int & n){
|
|
int j=0;
|
|
char *temp = new char[len];
|
|
while(isint(c[j+start])){
|
|
temp[j]=c[j+start];j++;
|
|
}
|
|
temp[j] = '\n';
|
|
n = atoi(temp);
|
|
delete[] temp;
|
|
|
|
return (j-1+start);//Exactly the length of the number
|
|
}
|
|
|
|
//Given a string starting with an open parentheses returns the place
|
|
// which marks the end of the corresponding closing parentheses.
|
|
//Strings of the form (A).
|
|
template <class NT>
|
|
int BiPoly<NT>::matchparen(const char* cstr, int start){
|
|
int count = 0;
|
|
int j=start;
|
|
|
|
do{
|
|
if(cstr[j] == '('){
|
|
count++;
|
|
}
|
|
if(cstr[j] == ')'){
|
|
count--;
|
|
}
|
|
j++;
|
|
}while(count != 0 );//j is one more than the matching ')'
|
|
|
|
return j-1;
|
|
}
|
|
|
|
|
|
template <class NT>
|
|
int BiPoly<NT>::getbasicterm(string s, BiPoly<NT> & P){
|
|
const char * cstr = s.c_str();
|
|
unsigned int len = s.length();
|
|
int i=0;
|
|
//BiPoly<NT> * temp = new BiPoly<NT>();
|
|
|
|
if(isint(cstr[i])){
|
|
i = getnumber(cstr, i, len, P);
|
|
}else if(cstr[i] == 'x'||cstr[i] == 'X'){
|
|
constructX(1, P);
|
|
}else if(cstr[i] == 'y'||cstr[i] == 'Y'){
|
|
constructY(1, P);
|
|
}else if(cstr[i] =='('){
|
|
int oldi = i;
|
|
i = matchparen(cstr, i);
|
|
string t = s.substr(oldi+1, i -oldi -1);
|
|
P = getbipoly(t);
|
|
}else if(cstr[i] == '-'){//Unary Minus
|
|
P.ydeg = 0;
|
|
P.deleteCoeffX();//Clear the present coeffecients
|
|
NT cs[] = {-1};
|
|
Polynomial<NT> q(0, cs);
|
|
P.coeffX.push_back(q);
|
|
}else{
|
|
std::cout <<"ERROR IN PARSING BASIC TERM" << std::endl;
|
|
}
|
|
//i+1 points to the beginning of next syntaxtic object in the string.
|
|
if(cstr[i+1] == '^'){
|
|
int n;
|
|
i = getint(cstr, i+2, len, n);
|
|
P.pow(n);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
|
|
template <class NT>
|
|
int BiPoly<NT>::getterm(string s, BiPoly<NT> & P){
|
|
unsigned int len = s.length();
|
|
if(len == 0){// Zero BiPoly
|
|
P = BiPoly<NT>();
|
|
return 0;
|
|
}
|
|
unsigned int ind, oind;
|
|
const char* cstr =s.c_str();
|
|
string t;
|
|
//P will be used to accumulate the product of basic terms.
|
|
ind = getbasicterm(s, P);
|
|
while(ind != len-1 && cstr[ind + 1]!='+' && cstr[ind + 1]!='-' ){
|
|
//Recursively get the basic terms till we reach the end or see
|
|
// a '+' or '-' sign.
|
|
if(cstr[ind + 1] == '*'){
|
|
t = s.substr(ind + 2, len - ind -2);
|
|
oind = ind + 2;
|
|
}else{
|
|
t = s.substr(ind + 1, len -ind -1);
|
|
oind = ind + 1;
|
|
}
|
|
|
|
BiPoly<NT> R;
|
|
ind = oind + getbasicterm(t, R);//Because the second term is the offset in
|
|
//t
|
|
P *= R;
|
|
}
|
|
|
|
return ind;
|
|
}
|
|
|
|
template <class NT>
|
|
BiPoly<NT> BiPoly<NT>::getbipoly(string s){
|
|
|
|
//Remove white spaces from the string
|
|
unsigned int cnt=s.find(' ',0);
|
|
while(cnt != string::npos){
|
|
s.erase(cnt, 1);
|
|
cnt = s.find(' ', cnt);
|
|
}
|
|
|
|
unsigned int len = s.length();
|
|
if(len <= 0){//Zero Polynomial
|
|
return BiPoly<NT>();
|
|
}
|
|
|
|
//To handle the case when there is one '=' sign
|
|
//Suppose s is of the form s1 = s2. Then we assign s to
|
|
//s1 + (-1)(s2) and reset len
|
|
unsigned int loc;
|
|
if((loc=s.find('=',0)) != string::npos){
|
|
s.replace(loc,1,1,'+');
|
|
string s3 = "(-1)(";
|
|
s.insert(loc+1, s3);
|
|
len = s.length();
|
|
s.insert(len, 1, ')');
|
|
}
|
|
len = s.length();
|
|
|
|
const char *cstr = s.c_str();
|
|
string t;
|
|
BiPoly<NT> P;
|
|
// P will be the polynomial in which we accumulate the
|
|
//sum and difference of the different terms.
|
|
unsigned int ind;
|
|
|
|
if(cstr[0] == '-'){
|
|
t = s.substr(1, len);
|
|
ind = getterm(t,P) + 1;
|
|
NT negone(-1);
|
|
P.mulScalar(negone);
|
|
}else{
|
|
ind = getterm(s, P);
|
|
}
|
|
|
|
unsigned int oind =0;//the string between oind and ind is a term
|
|
while(ind != len -1){
|
|
BiPoly<NT> R;
|
|
t = s.substr(ind + 2, len -ind -2);
|
|
oind = ind;
|
|
ind = oind + 2 + getterm(t, R);
|
|
if(cstr[oind + 1] == '+')
|
|
P += R;
|
|
else if(cstr[oind + 1] == '-')
|
|
P -= R;
|
|
else
|
|
std::cout << "ERROR IN PARSING BIPOLY! " << std::endl;
|
|
}
|
|
|
|
return P;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
// METHODS
|
|
////////////////////////////////////////////////////////
|
|
|
|
// filedump (msg, ofs, com, com2)
|
|
// where msg and com are strings.
|
|
// msg is an message and com is the character preceding each line
|
|
// (e.g., msg="" and com=com2="# ")
|
|
// This is called by the other dump functions
|
|
template <class NT>
|
|
void BiPoly<NT>::dump(std::ostream & os, std::string msg,
|
|
std::string com, std::string com2) const {
|
|
if (msg != "")
|
|
os << msg << std::endl;
|
|
if(ydeg == -1) {
|
|
os << com << " Zero Polynomial" << std::endl;
|
|
return;
|
|
}
|
|
bool first = true;
|
|
os << com;
|
|
for (int i=0; i <= ydeg; i++){
|
|
if (!zeroP(coeffX[i])){
|
|
if (i % 3 == 0) os << std::endl << com2 ; // output 3 coefficients per line
|
|
if (first) first = false;
|
|
else os << " + ";
|
|
os << "[";
|
|
coeffX[i].filedump(os,"","",com2); // Note: first comment string is ""
|
|
os << "]";
|
|
if (i > 0) os <<" * y^"<< i ;
|
|
}
|
|
}
|
|
}//dump
|
|
|
|
// dump(ofs, msg, com, com2) -- dump to file
|
|
//
|
|
/*
|
|
template <class NT>
|
|
void BiPoly<NT>::dump(std::ofstream & ofs, std::string msg,
|
|
std::string com, std::string com2) const {
|
|
dump(ofs, msg, com, com2);
|
|
}
|
|
*/
|
|
// dump(msg, com) -- dump to std output
|
|
template <class NT>
|
|
void BiPoly<NT>::dump(std::string msg, std::string com,
|
|
std::string com2) const {
|
|
dump(std::cout, msg, com, com2);
|
|
}
|
|
|
|
/* ***********************************************************
|
|
We want to substitute X or Y with a general Expression or BigFloat
|
|
into a BiPoly. E.g., the following produces a Y-polynomial
|
|
after replacing X by x:
|
|
|
|
BiPoly<NT> yPolynomial(const Expr & x) {
|
|
|
|
VecExpr vE;
|
|
for (int i=0; i<= ydeg; i++) {
|
|
vE.push_back(coeffX[i].eval(x));
|
|
}
|
|
return Polynomial<Expr>(vE);
|
|
}//yPolynomial
|
|
|
|
But this has many problems.
|
|
Solution below is to have special yExprPolynomial(x).
|
|
*********************************************************** */
|
|
|
|
template <class NT>
|
|
Polynomial<NT> BiPoly<NT>::yPolynomial(const NT & x) {
|
|
NT coeffVec[ydeg+1];
|
|
int d=-1;
|
|
for(int i=ydeg; i >= 0 ; i--){
|
|
coeffVec[i] = coeffX[i].eval(x);
|
|
if ((d < 0) && (coeffVec[i] != 0))
|
|
d = i;
|
|
}
|
|
return Polynomial<NT>(d, coeffVec);
|
|
}
|
|
|
|
// Specialized version of yPolynomial for Expressions
|
|
template <class NT>
|
|
Polynomial<Expr> BiPoly<NT>::yExprPolynomial(const Expr & x) {
|
|
Expr coeffVec[ydeg+1];
|
|
int d=-1;
|
|
for(int i=ydeg; i >= 0 ; i--){
|
|
coeffVec[i] = coeffX[i].eval(x);
|
|
if ((d < 0) && (coeffVec[i] != 0))
|
|
d = i;
|
|
}
|
|
return Polynomial<Expr>(d, coeffVec);
|
|
}
|
|
|
|
// Specialized version of yPolynomial for BigFloat
|
|
// ASSERTION: BigFloat x is exact
|
|
template <class NT>
|
|
Polynomial<BigFloat> BiPoly<NT>::yBFPolynomial(const BigFloat & x) {
|
|
BigFloat coeffVec[ydeg+1];
|
|
int d=-1;
|
|
for(int i=ydeg; i >= 0 ; i--){
|
|
coeffVec[i] = coeffX[i].eval(x);
|
|
if ((d < 0) && (coeffVec[i] != 0))
|
|
d = i;
|
|
}
|
|
return Polynomial<BigFloat>(d, coeffVec);
|
|
}
|
|
|
|
// xPolynomial(y)
|
|
// returns the polynomial (in X) when we substitute Y=y
|
|
//
|
|
// N.B. May need the
|
|
// Polynomial<Expr> xExprPolynomial(Expr y)
|
|
// version too...
|
|
//
|
|
|
|
template <class NT>
|
|
Polynomial<NT> BiPoly<NT>::xPolynomial(const NT & y) {
|
|
Polynomial<NT> res = coeffX[0];
|
|
NT yPower(y);
|
|
for(int i=1; i <= ydeg ; i++){
|
|
res += coeffX[i].mulScalar(yPower);
|
|
yPower *= y;
|
|
}
|
|
return res;
|
|
}//xPolynomial
|
|
|
|
|
|
// getYdegree()
|
|
template <class NT>
|
|
int BiPoly<NT>::getYdegree() const {
|
|
return ydeg;
|
|
}
|
|
|
|
// getXdegree()
|
|
template <class NT>
|
|
int BiPoly<NT>::getXdegree(){
|
|
int deg=-1;
|
|
for(int i=0; i <=ydeg; i++)
|
|
deg = max(deg, coeffX[i].getTrueDegree());
|
|
return deg;
|
|
}
|
|
|
|
// getTrueYdegree
|
|
template <class NT>
|
|
int BiPoly<NT>::getTrueYdegree(){
|
|
for (int i=ydeg; i>=0; i--){
|
|
coeffX[i].contract();
|
|
if (!zeroP(coeffX[i]))
|
|
return i;
|
|
}
|
|
return -1; // Zero polynomial
|
|
}//getTrueYdegree
|
|
|
|
|
|
//eval(x,y)
|
|
template <class NT>
|
|
Expr BiPoly<NT>::eval(Expr x, Expr y){//Evaluate the polynomial at (x,y)
|
|
Expr e = 0;
|
|
|
|
for(int i=0; i <=ydeg; i++){
|
|
e += coeffX[i].eval(x)*pow(y,i);
|
|
}
|
|
return e;
|
|
}//eval
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Polynomial arithmetic (these are all self-modifying)
|
|
////////////////////////////////////////////////////////
|
|
|
|
// Expands the nominal y-degree to n;
|
|
// Returns n if nominal y-degree is changed to n
|
|
// Else returns -2
|
|
|
|
template <class NT>
|
|
int BiPoly<NT>::expand(int n) {
|
|
if ((n <= ydeg)||(n < 0))
|
|
return -2;
|
|
|
|
for(int i=ydeg+1; i <=n ;i++)
|
|
coeffX.push_back(Polynomial<NT>::polyZero());
|
|
|
|
ydeg = n;
|
|
return n;
|
|
}//expand
|
|
|
|
// contract() gets rid of leading zero polynomials
|
|
// and returns the new (true) y-degree;
|
|
// It returns -2 if this is a no-op
|
|
|
|
template <class NT>
|
|
int BiPoly<NT>::contract() {
|
|
int d = getTrueYdegree();
|
|
if (d == ydeg)
|
|
return (-2); // nothing to do
|
|
else{
|
|
for (int i = ydeg; i> d; i--)
|
|
coeffX.pop_back();
|
|
ydeg = d;
|
|
}
|
|
return d;
|
|
}//contract
|
|
|
|
// Self-assignment
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::operator=( const BiPoly<NT>& P) {
|
|
if (this == &P)
|
|
return *this; // self-assignment
|
|
ydeg = P.getYdegree();
|
|
coeffX = P.coeffX;
|
|
return *this;
|
|
}//operator=
|
|
|
|
|
|
// Self-addition
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::operator+=( BiPoly<NT>& P) { // +=
|
|
|
|
int d = P.getYdegree();
|
|
if (d > ydeg)
|
|
expand(d);
|
|
for (int i = 0; i<=d; i++)
|
|
coeffX[i] += P.coeffX[i];
|
|
|
|
return *this;
|
|
}//operator+=
|
|
|
|
// Self-subtraction
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::operator-=( BiPoly<NT>& P) { // -=
|
|
int d = P.getYdegree();
|
|
if (d > ydeg)
|
|
expand(d);
|
|
for (int i = 0; i<=d; i++)
|
|
coeffX[i] -= P.coeffX[i];
|
|
|
|
return *this;
|
|
}//operator-=
|
|
|
|
// Self-multiplication
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::operator*=( BiPoly<NT>& P) { // *=
|
|
int d = ydeg + P.getYdegree();
|
|
|
|
std::vector<Polynomial<NT> > vP;
|
|
|
|
Polynomial<NT>* c = new Polynomial<NT> [d + 1];
|
|
for(int i=0; i <=d; i++)
|
|
c[i] = Polynomial<NT>();
|
|
|
|
for (int i = 0; i<=P.getYdegree(); i++)
|
|
for (int j = 0; j<=ydeg; j++) {
|
|
if(!zeroP(P.coeffX[i]) && !zeroP(coeffX[j]))
|
|
c[i+j] += P.coeffX[i] * coeffX[j];
|
|
}
|
|
|
|
for(int i=0; i <= d; i++)
|
|
vP.push_back(c[i]);
|
|
|
|
delete[] c;
|
|
coeffX.clear();
|
|
coeffX = vP;
|
|
ydeg = d;
|
|
return *this;
|
|
}//operator*=
|
|
|
|
// Multiply by a polynomial in X
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::mulXpoly( Polynomial<NT> & p) {
|
|
contract();
|
|
if (ydeg == -1)
|
|
return *this;
|
|
|
|
for (int i = 0; i<=ydeg ; i++)
|
|
coeffX[i] *= p;
|
|
return *this;
|
|
}//mulXpoly
|
|
|
|
//Multiply by a constant
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::mulScalar( NT & c) {
|
|
for (int i = 0; i<=ydeg ; i++)
|
|
coeffX[i].mulScalar(c);
|
|
return *this;
|
|
}//mulScalar
|
|
|
|
// mulYpower: Multiply by Y^i (COULD be a divide if i<0)
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::mulYpower(int s) {
|
|
// if s >= 0, then this is equivalent to
|
|
// multiplying by Y^s; if s < 0, to dividing by Y^s
|
|
if (s==0)
|
|
return *this;
|
|
int d = s+getTrueYdegree();
|
|
if (d < 0) {
|
|
ydeg = -1;
|
|
deleteCoeffX();
|
|
return *this;
|
|
}
|
|
|
|
std::vector<Polynomial<NT> > vP;
|
|
if(s > 0){
|
|
for(int i=0; i < s; i ++)
|
|
vP.push_back(Polynomial<NT>::polyZero());
|
|
for(int i=s; i<=d; i++)
|
|
vP.push_back(coeffX[i-s]);
|
|
}
|
|
|
|
if (s < 0) {
|
|
for (int j=-1*s; j <= d-s; j++)
|
|
vP.push_back(coeffX[j]);
|
|
}
|
|
|
|
coeffX = vP;
|
|
ydeg= d;
|
|
return *this;
|
|
}//mulYpower
|
|
|
|
|
|
|
|
// Divide by a polynomial in X.
|
|
// We replace the coeffX[i] by the pseudoQuotient(coeffX[i], P)
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::divXpoly( Polynomial<NT> & p) {
|
|
contract();
|
|
if (ydeg == -1)
|
|
return *this;
|
|
|
|
for (int i = 0; i<=ydeg ; i++)
|
|
coeffX[i] = coeffX[i].pseudoRemainder(p);
|
|
|
|
return *this;
|
|
}// divXpoly
|
|
|
|
|
|
|
|
//Using the standard definition of pseudRemainder operation.
|
|
// --No optimization!
|
|
template <class NT>
|
|
BiPoly<NT> BiPoly<NT>::pseudoRemainderY (BiPoly<NT> & Q){
|
|
contract();
|
|
Q.contract();
|
|
int qdeg = Q.getYdegree();
|
|
Polynomial<NT> LC(Q.coeffX[qdeg]), temp1(LC), temp;
|
|
BiPoly<NT> P(Q);
|
|
|
|
std::vector<Polynomial<NT> > S;//The quotient in reverse order
|
|
if(ydeg < qdeg){
|
|
return (*this);
|
|
}
|
|
(*this).mulXpoly(temp1.power(ydeg - qdeg +1));
|
|
|
|
while(ydeg >= qdeg){
|
|
temp1 = coeffX[ydeg];
|
|
temp = temp1.pseudoRemainder(LC);
|
|
S.push_back(temp);
|
|
P.mulXpoly(temp);
|
|
P.mulYpower(ydeg - qdeg);
|
|
*this -= P;
|
|
contract();
|
|
P = Q;//P is used as a temporary since mulXpower and mulYpower are
|
|
// self modifying
|
|
}
|
|
|
|
//Correct the order of S
|
|
std::vector<Polynomial<NT> > vP;
|
|
|
|
for(int i= S.size()-1; i>=0; i--)
|
|
vP.push_back(S[i]);
|
|
|
|
|
|
return BiPoly<NT>(vP);
|
|
|
|
}//pseudoRemainder
|
|
|
|
//Partial Differentiation
|
|
//Partial Differentiation wrt Y
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::differentiateY() {
|
|
if (ydeg >= 0) {
|
|
for (int i=1; i<=ydeg; i++)
|
|
coeffX[i-1] = coeffX[i].mulScalar(i);
|
|
ydeg--;
|
|
}
|
|
return *this;
|
|
}// differentiation wrt Y
|
|
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::differentiateX() {
|
|
if (ydeg >= 0)
|
|
for (int i=0; i<=ydeg; i++)
|
|
coeffX[i].differentiate();
|
|
|
|
return *this;
|
|
}// differentiation wrt X
|
|
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::differentiateXY(int m, int n) {//m times wrt X and n times wrt Y
|
|
assert(m >=0); assert(n >=0);
|
|
for(int i=1; i <=m; i++)
|
|
(*this).differentiateX();
|
|
for(int i=1; i <=n; i++)
|
|
(*this).differentiateY();
|
|
|
|
return *this;
|
|
}
|
|
|
|
//Represents the bivariate polynomial in (R[X])[Y] as a member
|
|
//of (R[Y])[X].
|
|
//But since our polynomials in X can only have NT coeff's thus
|
|
// to represent the above polynomial we switch X and Y once
|
|
// the conversion has been done.
|
|
//NOTE: This is different from replacing X by Y which was
|
|
// done in the case of the constructor from a polynomial in X
|
|
//Need to calculate resultant wrt X.
|
|
template <class NT>
|
|
BiPoly<NT> & BiPoly<NT>::convertXpoly(){
|
|
getTrueYdegree();
|
|
if(ydeg == -1) return (*this);
|
|
NT *cs = new NT[ydeg +1];
|
|
int xdeg = getXdegree();
|
|
std::vector<Polynomial<NT> > vP;
|
|
|
|
for(int i=0; i<=xdeg; i++){
|
|
for(int j=0; j<=ydeg; j++){
|
|
cs[j] = coeffX[j].getCoeffi(i);
|
|
}
|
|
|
|
vP.push_back(Polynomial<NT>(ydeg, cs));
|
|
}
|
|
delete[] cs;
|
|
|
|
ydeg = xdeg;
|
|
coeffX = vP;
|
|
return (*this);
|
|
}
|
|
|
|
//Set Coeffecient to the polynomial passed as a parameter
|
|
template <class NT>
|
|
bool BiPoly<NT>::setCoeff(int i, Polynomial<NT> p){
|
|
if(i < 0 || i > ydeg)
|
|
return false;
|
|
coeffX[i] = p;
|
|
return true;
|
|
}
|
|
|
|
template <class NT>
|
|
void BiPoly<NT>::reverse() {
|
|
Polynomial<NT> tmp;
|
|
for (int i=0; i<= ydeg/2; i++) {
|
|
tmp = coeffX[i];
|
|
coeffX[i] = coeffX[ydeg-i];
|
|
coeffX[ydeg-i] = tmp;
|
|
}
|
|
}//reverse
|
|
|
|
//replaceYwithX()
|
|
// used used when the coeffX in BiPoly are constants,
|
|
// to get the corresponding univariate poly in X
|
|
// E.g., Y^2+2*Y+9 will be converted to X^2+2*X+9
|
|
template <class NT>
|
|
Polynomial<NT> BiPoly<NT>::replaceYwithX(){
|
|
int m = getTrueYdegree();
|
|
NT *cs = new NT[m+1];
|
|
for(int i=0; i <= m ; i++)
|
|
cs[i]=coeffX[i].getCoeffi(0);
|
|
delete[] cs;
|
|
|
|
return Polynomial<NT>(m,cs);
|
|
}//replaceYwithX
|
|
|
|
template <class NT>
|
|
BiPoly<NT>& BiPoly<NT>::pow(unsigned int n){
|
|
|
|
if (n == 0) {
|
|
ydeg = 0;
|
|
deleteCoeffX();
|
|
Polynomial<NT> unity(0);
|
|
coeffX.push_back(unity);
|
|
}else if(n == 1){
|
|
|
|
}else{
|
|
BiPoly<NT> x(*this);
|
|
|
|
while ((n % 2) == 0) { // n is even
|
|
x *= x;
|
|
n >>= 1;
|
|
}
|
|
BiPoly<NT> u(x);
|
|
while (true) {
|
|
n >>= 1;
|
|
if (n == 0){
|
|
(*this) = u;
|
|
return (*this);
|
|
}
|
|
x *= x;
|
|
if ((n % 2) == 1) // n is odd
|
|
u *= x;
|
|
}
|
|
(*this) = u;
|
|
}
|
|
return (*this);
|
|
}//pow
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Helper Functions
|
|
////////////////////////////////////////////////////////
|
|
|
|
// isZeroPinY(P)
|
|
// checks whether a Bi-polynomial is a zero Polynomial
|
|
template <class NT>
|
|
bool isZeroPinY(BiPoly<NT> & P){
|
|
if(P.getTrueYdegree() == -1)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// gcd(P,Q)
|
|
// This gcd is based upon the subresultant PRS to avoid
|
|
// exponential coeffecient growth and gcd computations, both of which
|
|
// are expensive since the coefficients are polynomials
|
|
|
|
template <class NT>
|
|
BiPoly<NT> gcd( BiPoly<NT>& P ,BiPoly<NT>& Q){
|
|
int m = P.getTrueYdegree();
|
|
int n = Q.getTrueYdegree();
|
|
|
|
//If both Bi-Polys are zero then return zero
|
|
if( m==-1 && n==-1){
|
|
return BiPoly<NT>();//Had to do this for the type of
|
|
//return value o/w causes problem in
|
|
} //assignment operation
|
|
|
|
if(m < n) {
|
|
return gcd(Q, P);
|
|
}
|
|
|
|
//If one of the Bi-Polys are zero then return the other
|
|
if(n==-1)
|
|
return P;
|
|
|
|
//When the two BiPolys are just univariate Polynomials in X
|
|
if(m==0 && n==0){
|
|
std::vector<Polynomial<NT> > vP;
|
|
vP.push_back(gcd(P.coeffX[0], Q.coeffX[0]));
|
|
return BiPoly<NT>(vP);//Had to do this for the type of
|
|
//return value
|
|
}
|
|
|
|
int delta = m - n;
|
|
Polynomial<NT> a(Q.coeffX[n]);
|
|
std::vector<NT> vN;
|
|
vN.push_back(pow(BigInt(-1),delta + 1));
|
|
Polynomial<NT> beta(vN);
|
|
Polynomial<NT> phi(power(a, delta)), t;
|
|
m = n;
|
|
BiPoly<NT> temp;
|
|
P.pseudoRemainderY(Q);
|
|
|
|
while(!isZeroPinY(P)){
|
|
P.divXpoly(beta);
|
|
n = P.getTrueYdegree();
|
|
delta = m - n;
|
|
beta = power(phi, delta)*a.mulScalar(pow(BigInt(-1),delta+1));
|
|
a = P.coeffX[n];
|
|
t = power(phi, delta -1);
|
|
phi = power(a,delta).pseudoRemainder(t);
|
|
m = n;
|
|
temp = Q;//Swapping the pseudo-remainder for the next step
|
|
Q = P;
|
|
P = temp;
|
|
P.pseudoRemainderY(Q);
|
|
}
|
|
return Q;
|
|
}//gcd
|
|
|
|
// resY(P,Q):
|
|
// Resultant of Bi-Polys P and Q w.r.t. Y.
|
|
// So the resultant is a polynomial in X
|
|
template <class NT>
|
|
Polynomial<NT> resY( BiPoly<NT>& P ,BiPoly<NT>& Q){
|
|
|
|
int m = P.getTrueYdegree();
|
|
int n = Q.getTrueYdegree();
|
|
|
|
//If either polynomial is zero, return zero
|
|
if( m == -1 || n == -1) return Polynomial<NT>();//::polyZero();
|
|
|
|
if(n > m)
|
|
return resY(Q, P);
|
|
|
|
Polynomial<NT> b(Q.coeffX[n]);
|
|
Polynomial<NT> lc(P.coeffX[m]), C, temp;
|
|
BiPoly<NT> r;
|
|
|
|
r = P.pseudoRemainderY(Q);
|
|
C = b * r.coeffX[r.getTrueYdegree()];
|
|
C = C.pseudoRemainder(lc);
|
|
|
|
if(isZeroPinY(P) && n > 0)
|
|
return Polynomial<NT>();//::polyZero();
|
|
|
|
if(Q.getTrueYdegree() == 0 && isZeroPinY(P))
|
|
return power(Q.coeffX[0], m);
|
|
|
|
int l = P.getTrueYdegree();
|
|
|
|
temp = power(b, m-l).mulScalar(pow(BigInt(-1),m*n))*resY(Q,P);
|
|
temp = temp.pseudoRemainder(power(C,n));
|
|
return temp;
|
|
|
|
}//resY
|
|
|
|
// resX(P,Q):
|
|
// Resultant of Bi-Polys P and Q w.r.t. X.
|
|
// So the resultant is a polynomial in Y
|
|
// We first convert P, Q to polynomials in X. Then
|
|
// call resY and then turns it back into a polynomial in Y
|
|
// QUESTION: is this last switch really necessary???
|
|
template <class NT>
|
|
BiPoly<NT> resX( BiPoly<NT>& P ,BiPoly<NT>& Q){
|
|
P.convertXpoly();
|
|
Q.convertXpoly();
|
|
|
|
// Polynomial<NT> p(resY(P,Q));
|
|
// return BiPoly<NT>(p);
|
|
return(resY(P,Q)); // avoid the switch back
|
|
}//resX
|
|
|
|
|
|
//Equality operator for BiPoly
|
|
template <class NT>
|
|
bool operator==(const BiPoly<NT>& P, const BiPoly<NT>& Q) { // ==
|
|
BiPoly<NT> P1(P);
|
|
BiPoly<NT> Q1(Q);
|
|
P1.contract();
|
|
Q1.contract();
|
|
if(P1.getYdegree() != Q1.getYdegree())
|
|
return false;
|
|
else{
|
|
for(int i=0; i <= P1.getYdegree() ; i++){
|
|
if(P1.coeffX[i] != Q1.coeffX[i])
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Addition P + Q
|
|
template <class NT>
|
|
BiPoly<NT> operator+(const BiPoly<NT>& P, const BiPoly<NT>& Q ) { // +
|
|
return BiPoly<NT>(P) += Q;
|
|
}
|
|
// Subtraction P - Q
|
|
template <class NT>
|
|
BiPoly<NT> operator-(const BiPoly<NT>& P,const BiPoly<NT>& Q ) { // +
|
|
return BiPoly<NT>(P) -= Q;
|
|
}
|
|
|
|
// Multiplication P * Q
|
|
template <class NT>
|
|
BiPoly<NT> operator*(const BiPoly<NT>& P, const BiPoly<NT>& Q ) { // +
|
|
return BiPoly<NT>(P) *= Q;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
//Curve Class
|
|
// extends BiPoly Class
|
|
////////////////////////////////////////////////////////
|
|
|
|
template < class NT >
|
|
Curve<NT>::Curve(){} // zero polynomial
|
|
|
|
//Curve(vp):
|
|
// construct from a vector of polynomials
|
|
template < class NT >
|
|
Curve<NT>::Curve(std::vector<Polynomial<NT> > vp)
|
|
: BiPoly<NT>(vp){
|
|
}
|
|
|
|
//Curve(p):
|
|
// Converts a polynomial p(X) to a BiPoly in one of two ways:
|
|
// (1) if flag is false, the result is Y-p(X)
|
|
// (2) if flag is true, the result is p(Y)
|
|
// The default is (1) because we usually want to plot the
|
|
// graph of the polynomial p(X)
|
|
template < class NT >
|
|
Curve<NT>::Curve(Polynomial<NT> p, bool flag)
|
|
: BiPoly<NT>(p, flag){
|
|
}
|
|
|
|
//Curve(deg, d[], C[]):
|
|
// Takes in a list of list of coefficients.
|
|
// Each cofficient list represents a polynomial in X
|
|
//
|
|
// deg - ydeg of the bipoly
|
|
// d[] - array containing the degrees of each coefficient (i.e., X poly)
|
|
// C[] - list of coefficients, we use array d to select the
|
|
// coefficients
|
|
template < class NT >
|
|
Curve<NT>::Curve(int deg, int *d, NT *C)
|
|
: BiPoly<NT>(deg, d, C){
|
|
}
|
|
|
|
template < class NT >
|
|
Curve<NT>::Curve(const BiPoly<NT> &P)
|
|
: BiPoly<NT>(P){
|
|
}
|
|
|
|
//Curve(n)
|
|
template < class NT >
|
|
Curve<NT>::Curve(int n)
|
|
: BiPoly<NT>(n){// creates a Curve with nominal y-degree equal to n
|
|
}
|
|
|
|
//Creates a curve from a string (no parentheses, no *)
|
|
template < class NT >
|
|
Curve<NT>::Curve(const string & s, char myX, char myY)
|
|
: BiPoly<NT>(s, myX, myY){
|
|
}
|
|
template < class NT >
|
|
Curve<NT>::Curve(const char * s, char myX, char myY)
|
|
: BiPoly<NT>(s, myX, myY){
|
|
}
|
|
|
|
|
|
// verticalIntersections(x, vecI, aprec=0):
|
|
//
|
|
// The list vecI is passed an isolating intervals for y's such that (x,y)
|
|
// lies on the curve.
|
|
// If aprec is non-zero (!), the intervals have with < 2^{-aprec}.
|
|
// Return is -2 if curve equation does not depend on Y
|
|
// -1 if infinitely roots at x,
|
|
// 0 if no roots at x
|
|
// 1 otherwise
|
|
//
|
|
// ASSERTION: x is an exact BigFloat
|
|
|
|
template < class NT >
|
|
int Curve<NT>::verticalIntersections(const BigFloat & x, BFVecInterval & vI,
|
|
int aprec) {
|
|
int d= Curve<NT>::getTrueYdegree();
|
|
if(d <= 0) return(-2);
|
|
// This returns a NULL vI, which should be caught by caller
|
|
|
|
Polynomial<Expr> PY = this->yExprPolynomial(x); // should be replaced
|
|
// assert(x.isExact());
|
|
// Polynomial<BigFloat> PY = yBFPolynomial(x); // unstable still
|
|
|
|
d = PY.getTrueDegree();
|
|
if(d <= 0) return(d);
|
|
|
|
Sturm<Expr> SS(PY); // should be replaced by BigFloat version
|
|
// Sturm<BigFloat> SS(PY); // unstable still
|
|
SS.isolateRoots(vI);
|
|
|
|
int s = vI.size();
|
|
if ((aprec != 0) && (s>0))
|
|
SS.newtonRefineAllRoots(vI, aprec);
|
|
|
|
return s;
|
|
}
|
|
|
|
// plot(eps, x1, y1, x2, y2)
|
|
//
|
|
// All parameters have defaults
|
|
//
|
|
// Gives the points on the curve at resolution "eps". Currently,
|
|
// eps is viewed as delta-x step size (but it could change).
|
|
// The display is done in the rectangale
|
|
// defined by [(x1, y1), (x2, y2)].
|
|
// The output is written into a file in the format specified
|
|
// by our drawcurve function (see COREPATH/ext/graphics).
|
|
//
|
|
// Heuristic: the open polygonal lines end when number of roots
|
|
// changes...
|
|
//
|
|
// TO DO:
|
|
// (1) need to automatically readjust x- and y-scales
|
|
// independently
|
|
// (2) reorder parameters in this order: x1, x2, y1, y2
|
|
// [Then y1, y2 can be automatically determined]
|
|
// (3) should allow the ability to look for interesting
|
|
// features
|
|
//
|
|
// ASSERTION: all input BigFloats are exact
|
|
//
|
|
template < class NT >
|
|
int Curve<NT>::plot( BigFloat eps, BigFloat x1,
|
|
BigFloat y1, BigFloat x2, BigFloat y2, int fileNo){
|
|
|
|
const char* filename[] = {"data/input", "data/plot", "data/plot2"};
|
|
|
|
assert(eps.isExact()); // important for plotting...
|
|
assert(x1.isExact());
|
|
assert(y1.isExact());
|
|
|
|
ofstream outFile;
|
|
outFile.open(filename[fileNo]); // ought to check if open is successful!
|
|
outFile << "########################################\n";
|
|
outFile << "# Curve equation: \n";
|
|
this->dump(outFile,"", "# ");
|
|
outFile << std::endl;
|
|
outFile << "# Plot parameters: step size (eps) = " << eps << std::endl;
|
|
outFile << "# x1 = " << x1 << ",\t y1 = " << y1 << std::endl;
|
|
outFile << "# x2 = " << x2 << ",\t y2 = " << y2 << std::endl;
|
|
outFile << "########################################\n";
|
|
outFile << "# X-axis " << std::endl;
|
|
outFile << "o 2" << std::endl;
|
|
outFile << "0.99 \t 0.99 \t 0.99" << std::endl;
|
|
outFile << x1 << "\t" << 0 << std::endl;
|
|
outFile << x2 << "\t" << 0 << std::endl;
|
|
outFile << "########################################\n";
|
|
outFile << "# Y-axis " << std::endl;
|
|
outFile << "o 2" << std::endl;
|
|
outFile << "0.99 \t 0.99 \t 0.99" << std::endl;
|
|
outFile << 0 << "\t" << y1 << std::endl;
|
|
outFile << 0 << "\t" << y2 << std::endl;
|
|
// assert(eps>0)
|
|
int aprec = -(eps.lMSB()).toLong(); // By definition, eps.lMSB() <= lg(eps)
|
|
|
|
BigFloat xCurr = x1;
|
|
BigFloat xLast = x1;
|
|
unsigned int numRoots=0;
|
|
unsigned int numPoints=0;
|
|
BFVecInterval vI;
|
|
|
|
cout <<"Current value of x " << xCurr << endl;
|
|
//===================================================================
|
|
// FIRST locate the first x-value where there are roots for plotting
|
|
//===================================================================
|
|
do {
|
|
vI.clear();
|
|
if (verticalIntersections(xCurr, vI, aprec) > 0) {
|
|
numRoots = vI.size();
|
|
cout <<"Number of roots at " << xCurr << " are " << numRoots<<endl;
|
|
}
|
|
xCurr += eps;
|
|
|
|
} while ((numRoots == 0) && (xCurr < x2));//numRoots <= ydeg
|
|
|
|
if (numRoots == 0 && x2 <= xCurr) {//if numRoots > 0 then there exists a
|
|
//valid point for plotting
|
|
return -1; // nothing to plot!
|
|
}
|
|
|
|
int limit = ((x2 - xCurr + eps)/eps).intValue()+1;
|
|
//std::cout << "Limit = " << limit << std::endl;
|
|
machine_double plotCurves[this->getTrueYdegree()][limit];//plot buffer
|
|
machine_double yval;
|
|
|
|
for (unsigned int i=0; i< numRoots; i++) {
|
|
yval = (vI[i].first + vI[i].second).doubleValue()/2;
|
|
if (yval < y1) plotCurves[i][numPoints] = y1.doubleValue();
|
|
else if (yval > y2) plotCurves[i][numPoints] = y2.doubleValue();
|
|
else plotCurves[i][numPoints] = yval;
|
|
}
|
|
|
|
vI.clear();
|
|
xLast = xCurr - eps; // -eps to compensate for the forward value of xCurr
|
|
numPoints = 1;
|
|
|
|
//===================================================================
|
|
// Get all the curves in a main loop
|
|
// -- dump the curves when an x-interval is discovered
|
|
// We define an "x-interval" to be a maximal interval
|
|
// where the number of curves is constant (this is a heuristic!)
|
|
// Note that this includes the special case where number is 0.
|
|
//===================================================================
|
|
|
|
BigFloat tmp; // used to step from xLast to xCurr in loops
|
|
|
|
while (xCurr < x2) { //main loop
|
|
//std::cout << "Doing verticalintersec at " << xCurr << std::endl;
|
|
verticalIntersections(xCurr, vI, aprec);
|
|
if (vI.size() != numRoots) { // an x-interval discovered!
|
|
// write previous x-interval to output file
|
|
outFile << "########################################\n";
|
|
outFile << "# New x-interval with " << numRoots << " roots\n";
|
|
for (unsigned int i=0; i< numRoots; i++) {
|
|
outFile << "#=======================================\n";
|
|
outFile << "# Curve No. " << i+1 << std::endl;
|
|
outFile << "o " << numPoints << std::endl;
|
|
outFile << red_comp(i) << "\t"
|
|
<< green_comp(i) << "\t"
|
|
<< blue_comp(i) << std::endl;
|
|
tmp = xLast;
|
|
for (unsigned int j=0; j< numPoints; j++) {
|
|
|
|
outFile << tmp << " \t\t"
|
|
<< plotCurves[i][j] << "\n";
|
|
tmp += eps;
|
|
}//for j
|
|
}//for i
|
|
numPoints = 0; // reset
|
|
numRoots = vI.size(); // reset
|
|
xLast = xCurr; // reset
|
|
}//if vI.size() !=
|
|
if (numRoots>0){ // record curr. vertical intersections if numRoots>0
|
|
for (unsigned int i=0; i< numRoots; i++) {
|
|
yval = (vI[i].first + vI[i].second).doubleValue()/2;
|
|
// HERE SHOULD BE A LOOP TO OUTPUT MORE POINTS IN CASE THE slope IS LARGE
|
|
// Idea: let previous value of yval be yval-old.
|
|
//
|
|
// Two cases:
|
|
// (1) When i=0:
|
|
// you need to search backwards and forwards
|
|
// (yval-old is not defined in this case)
|
|
//
|
|
// (2) When i>0:
|
|
// If |yval-old - yval| > 2eps, we must plot using horizontalIntersection()
|
|
// We must start from
|
|
// y = yval-old until
|
|
// EITHER (y = (vI[i+1].first + vI[i+1].second)/2)
|
|
// OR (sign of slope changes)
|
|
// OR (hit the ymax or ymin boundary)
|
|
//
|
|
if (yval < y1) plotCurves[i][numPoints] = y1.doubleValue();
|
|
else if (yval > y2) plotCurves[i][numPoints] = y2.doubleValue();
|
|
else plotCurves[i][numPoints] = yval;
|
|
}//for i
|
|
vI.clear(); //Should clear the intersection points
|
|
numPoints++;
|
|
}//if
|
|
xCurr += eps;
|
|
if (!xCurr.isExact()) std::cout<<"xCurr has error! xCurr=" << xCurr << std::endl;
|
|
}//main while loop
|
|
|
|
// Need to flush out the final x-interval:
|
|
if ((numRoots>0) && (numPoints >0)) {
|
|
// write to output file
|
|
outFile << "########################################\n";
|
|
outFile << "# New x-interval with " << numRoots << " roots\n";
|
|
for (unsigned int i=0; i< numRoots; i++) {
|
|
outFile << "#=======================================\n";
|
|
outFile << "# Curve No. " << i+1 << std::endl;
|
|
outFile << "o " << numPoints << std::endl;
|
|
outFile << red_comp(i) << "\t"
|
|
<< green_comp(i) << "\t"
|
|
<< blue_comp(i) << std::endl;
|
|
tmp = xLast;
|
|
for (unsigned int j=0; j< numPoints; j++) {
|
|
|
|
outFile << tmp << " \t\t"
|
|
<< plotCurves[i][j] << "\n";
|
|
tmp += eps;
|
|
}//for j
|
|
}//for i
|
|
}//if
|
|
|
|
// Put out the final frame (this hides the artificial cut-off of curves
|
|
outFile << "########################################\n";
|
|
outFile << "# FRAME around our figure " << std::endl;
|
|
outFile << "p 4" << std::endl;
|
|
outFile << "0.99 \t 0.99 \t 0.99" << std::endl;
|
|
outFile << x1 << "\t" << y1 << std::endl;
|
|
outFile << x2 << "\t" << y1 << std::endl;
|
|
outFile << x2 << "\t" << y2 << std::endl;
|
|
outFile << x1 << "\t" << y2 << std::endl;
|
|
outFile << "######### End of File ##################\n";
|
|
|
|
outFile.close();
|
|
return 0;
|
|
}//plot
|
|
|
|
// selfIntersections():
|
|
// this should be another member function that lists
|
|
// all the self-intersections of a curve
|
|
//
|
|
// template <class NT>
|
|
// void selfIntersections(BFVecInterval &vI){
|
|
// ...
|
|
// }
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Curve helper functions
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
|
//Xintersections(C, D, vI):
|
|
// returns the list vI of x-ccordinates of possible intersection points.
|
|
// Assumes that C & D are quasi-monic.(or generally aligned)
|
|
template <class NT>
|
|
void Xintersections( Curve<NT>& P ,Curve<NT>& Q, BFVecInterval &vI){
|
|
Sturm<NT> SS(resY(P, Q));
|
|
SS.isolateRoots(vI);
|
|
}
|
|
|
|
//Yintersections(C, D, vI):
|
|
// similar to Xintersections
|
|
template <class NT>
|
|
void Yintersections( Curve<NT>& P ,Curve<NT>& Q, BFVecInterval &vI){
|
|
Sturm<NT> SS(resX(P, Q));
|
|
SS.isolateRoots(vI);
|
|
}
|
|
|
|
// Display Intervals
|
|
//
|
|
template <class NT>//DO I NEED THIS OVERHERE AS WELL?
|
|
void showIntervals(char* s, BFVecInterval &vI) {
|
|
std::cout << s;
|
|
for (unsigned int i=0; i< vI.size(); i++) {
|
|
std::cout << "[ " << vI[i].first << ", "
|
|
<< vI[i].second << " ], " ;
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
|
|
/*************************************************************************** */
|
|
// END
|
|
/*************************************************************************** */
|
|
|