001package cnslab.cnsmath; 002import java.util.TreeSet; 003//this could be implemented as a sparse array 004//which would make evaluation faster, but PLD slower! 005public class Polynomial 006{ 007 //the ith order term coefficient is in the ith spot: 008 public double[] coefficients; 009 public TreeSet<KCelement> poolKC; 010 public Polynomial Q; 011 public double minAccuracy=1e-8; 012 013 public Polynomial(double[] coefficients) 014 { 015 this.coefficients=coefficients; 016 } 017 018 public int getDegree() 019 { 020 return coefficients.length-1; 021 } 022/* 023 public double evaluate(double x) 024 { 025 double sum=0.0; 026 for(int exponent=0;exponent<coefficients.length;exponent++) 027 sum+=coefficients[exponent]*Math.pow(x,exponent); 028 return sum; 029 } 030*/ 031 032 public double evaluate(double x) 033 { 034 double sum=0.0; 035 sum = coefficients[coefficients.length-1]; 036 for(int exponent=coefficients.length-2 ;exponent >= 0;exponent--) 037 { 038 sum = x*sum+coefficients[exponent]; 039 } 040 return sum; 041 } 042 043 public double evaluateAtZero() 044 { 045 return coefficients[0]; 046 } 047 048 public double evaluateAtOne() 049 { 050 double sum=0.0; 051 for(int exponent=0;exponent<coefficients.length;exponent++) 052 sum+=coefficients[exponent]; 053 return sum; 054 } 055 056 public Polynomial talorShiftOne() //g(x)=f(x+1) 057 { 058 double [] out = new double[coefficients.length]; 059 out[0] = coefficients[coefficients.length-1]; 060 for(int i=1; i< coefficients.length; i++) 061 { 062 out[i] = out[i-1]; 063 double tmp= out[0]; 064 double tmp2= out[1]; 065 for(int j=1; j< i; j++) 066 { 067 out[j] = out[j]+tmp; 068 tmp=tmp2; 069 tmp2=out[j+1]; 070 } 071 out[0] = out[0]+coefficients[coefficients.length-i-1]; 072 /* 073 for(int j=0;j<i+1;j++) 074 System.out.print(out[j]+" "); 075 System.out.println(); 076 */ 077 } 078 return new Polynomial(out); 079 } 080 081 082 public Polynomial talorShift(double n) //g(x)=f(x+n) 083 { 084 return this.H(n).talorShiftOne().H(1.0/n); 085 086 } 087 088 public Polynomial H(double n) //g(x)=f(nx) 089 { 090 double [] out = new double[coefficients.length]; 091 out[0] = coefficients[coefficients.length-1]; 092 for(int i=1; i< coefficients.length; i++) 093 { 094 for(int j=i; j>= 1; j--) 095 { 096 out[j] = out[j-1]*n; 097 } 098 out[0] = coefficients[coefficients.length-i-1]; 099 /* 100 for(int j=0;j<i+1;j++) 101 System.out.print(out[j]+" "); 102 System.out.println(); 103 */ 104 } 105 return new Polynomial(out); 106 } 107 108 public Polynomial reverse() { 109 double [] out = new double[coefficients.length]; 110 System.arraycopy(coefficients,0,out,0,coefficients.length); 111 int i = 0; 112 int j = coefficients.length - 1; 113 double tmp; 114 while (j > i) { 115 tmp = out[j]; 116 out[j] = out[i]; 117 out[i] = tmp; 118 j--; 119 i++; 120 } 121 return new Polynomial(out); 122 } 123 124 public int count() { 125 int count=0; 126 boolean lastNeg=false; 127 boolean lastPos=false; 128 129 if(coefficients[0]>0) 130 lastPos=true; 131 else if(coefficients[0]<0) 132 lastNeg=true; 133 134 135 for(int i=1; i< coefficients.length; i++) 136 { 137 if(coefficients[i]>0&&lastNeg){ 138 count++; 139 lastPos=true; 140 lastNeg=false; 141 } 142 else if(coefficients[i]<0&&lastPos){ 143 count++; 144 lastPos=false; 145 lastNeg=true; 146 } 147 else if(coefficients[i]<0&&!lastPos){ 148 lastNeg=true; 149 } 150 else if(coefficients[i]>0&&!lastNeg){ 151 lastPos=true; 152 } 153 } 154 return count; 155 } 156 157 public int desBound() { 158 return this.reverse().talorShiftOne().count(); 159 } 160 161 public Polynomial scale(double n) 162 { 163 double [] out = new double[coefficients.length]; 164 System.arraycopy(coefficients,0,out,0,coefficients.length); 165 for(int i=0;i<out.length;i++)out[i]*=n; 166 return new Polynomial(out); 167 } 168 169 public double largestRoot() // return the largest Root in interval (0,1) or -1.0 for no root 170 { 171 if(this.count()==0) 172 { 173 return -1.0; 174 } 175 else 176 { 177 return 1.0-this.H(-1.0).talorShift(-1.0).smallestRoot(); 178 } 179 } 180 181 public double pow2(int expo) 182 { 183 if(expo>0) 184 { 185 return (double)(1<<expo); 186 } 187 else if(expo<0) 188 { 189 return 1.0/((double)(1<<(-expo))); 190 } 191 else 192 { 193 return 1.0; 194 } 195 } 196 197 public double smallestRoot() { // return the smallerst Root in interval (0,1) or -1.0 for no root 198 if(this.count()==0)return -1.0; 199// System.out.println("root of "+ this); 200 poolKC = new TreeSet<KCelement>(); 201 poolKC.add(new KCelement(0,0)); 202 double [] a = new double [coefficients.length]; 203 System.arraycopy(coefficients,0,a,0,coefficients.length); 204 Q= new Polynomial(a); 205 206 KCelement first,old; 207 old = new KCelement(0,0); 208 209 while((first=poolKC.pollFirst())!=null) 210 { 211 if(first.k==32){ 212 throw new RuntimeException("k:"+first.k+"c:"+first.c+" poly:"+this.toString()); 213 //continue; //it is a mutiply root 214 } 215// System.out.println(first); 216// System.out.println(Q); 217 if((int)(pow2(old.k-first.k)*(double)first.c-old.c)==1) 218 { 219 Q = Q.talorShiftOne().H(pow2(old.k-first.k)).scale(pow2(((coefficients.length-1)*(first.k-old.k)))); 220 } 221 else if((int)(pow2(old.k-first.k)*(double)first.c-old.c)==0) 222 { 223 Q = Q.H(pow2(old.k-first.k)).scale(pow2(((coefficients.length-1)*(first.k-old.k)))); 224 } 225 else 226 { 227 throw new RuntimeException("no shift ("+first.c+","+first.k+") old kc ("+old.c+","+old.k+")"); 228 } 229 230 int countRoot = Q.desBound(); 231// System.out.println("desBound count:"+countRoot); 232 if(countRoot ==1) 233 { 234// System.out.println("left:"+(double)first.c/(double)(1<<first.k)+" right:"+(double)(first.c+1)/(double)(1<<first.k)); 235// 236 return safeRootFind(this, (double)first.c/(double)(1<<first.k) ,(double)(first.c+1)/(double)(1<<first.k)); 237 } 238 else if (countRoot >1) 239 { 240 if(Math.abs(Q.evaluate(0.5))<minAccuracy)return (2*(double)first.c+1.0)/(double)(1<<first.k+1); 241 poolKC.add(new KCelement(2*first.c,first.k+1)); 242 poolKC.add(new KCelement(2*first.c+1,first.k+1)); 243// System.out.println("add two size "+poolKC.size()); 244 245 } 246 old = first; 247 } 248// System.out.println("not found"); 249 return -1.0; 250 } 251 252 public Polynomial df() 253 { 254 double[] dPrimeCoefs=new double[coefficients.length-1]; 255 for(int a=1;a<coefficients.length;a++) 256 { 257 dPrimeCoefs[a-1]=coefficients[a]*a; 258 } 259 return (new Polynomial(dPrimeCoefs)); 260 } 261 262 public double safeRootFind(Polynomial Q, double guess, double end) 263 { 264 Polynomial dQ=Q.df(); 265 int MAXIT=100; 266 double f1,fh; 267 double xl,xh; 268 f1=Q.evaluate(guess); 269 fh=Q.evaluate(end); 270 if( (f1>0 && fh >0) || (f1<0 && fh <0) )throw new RuntimeException("not bracketed"); 271 if(Math.abs(f1)<minAccuracy)return guess; 272 //if(Math.abs(fh)<minAccuracy)return end; 273 if(f1 <0.0) 274 { 275 xl=guess; 276 xh=end; 277 } 278 else 279 { 280 xh=guess; 281 xl=end; 282 } 283 double rts = 0.5*(xl+xh); 284 double fvalue=Q.evaluate(rts); 285 double dfvalue=dQ.evaluate(rts); 286 double dxold = Math.abs(xh-xl); 287 double dx=dxold; 288 double temp; 289 for( int j=0; j< MAXIT; j++) 290 { 291 if((((rts-xh)*dfvalue-fvalue)*((rts-xl)*dfvalue-fvalue)>0.0) || (Math.abs(2.0*fvalue) > Math.abs(dxold*dfvalue))) //out of range or slow convergent then bisection 292 { 293 dxold = dx; 294 dx=0.5*(xh-xl); 295 rts=xl+dx; 296 if(xl == rts) return rts; 297 } 298 else //Newton method 299 { 300 dxold=dx; 301 dx = fvalue/dfvalue; 302 temp = rts; 303 rts -= dx; 304 if(temp == rts) return rts; 305 } 306 if( Math.abs(dx)<minAccuracy) return rts; 307 fvalue=Q.evaluate(rts); 308 dfvalue=dQ.evaluate(rts); 309 if( fvalue<0) 310 { 311 xl=rts; 312 } 313 else 314 { 315 xh=rts; 316 } 317 } 318 throw new RuntimeException("max iteration"); 319 // return 0.0; 320 } 321 322 323 public String toString() 324 { 325 String ans=""; 326 if(coefficients.length>0) 327 ans+=coefficients[0]; 328 329 for(int a=1;a<coefficients.length;a++) 330 { 331 if(coefficients[a]!=0.0) 332 ans+=" + " + coefficients[a] + "*x^" + a; 333 } 334 return ans; 335 } 336 337 338}