source: src/main/java/agents/anac/y2015/agentBuyogV2/flanagan/roots/RealRoot.java

Last change on this file was 127, checked in by Wouter Pasman, 6 years ago

#41 ROLL BACK of rev.126 . So this version is equal to rev. 125

File size: 71.7 KB
Line 
1/*
2* Class RealRoot
3*
4* Contains methods for finding a real root
5*
6* The function whose root is to be determined is supplied
7* by means of an interface, RealRootFunction,
8* if no derivative required
9*
10* The function whose root is to be determined is supplied
11* by means of an interface, RealRootDerivFunction,
12* as is the first derivative if a derivative is required
13*
14* WRITTEN BY: Dr Michael Thomas Flanagan
15*
16* DATE: 18 May 2003
17* UPDATE: May 2003 - March 2008, 23-24 September 2008, 30 January 2010
18*
19* DOCUMENTATION:
20* See Michael Thomas Flanagan's Java library on-line web page:
21* http://www.ee.ucl.ac.uk/~mflanaga/java/RealRoot.html
22* http://www.ee.ucl.ac.uk/~mflanaga/java/
23*
24* Copyright (c) 2003 - 2010 Michael Thomas Flanagan
25*
26* Permission to use, copy and modify this software and its documentation for NON-COMMERCIAL purposes is granted, without fee,
27* provided that an acknowledgement to the author, Dr Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies
28* and associated documentation or publications.
29*
30* Redistributions of the source code of this source code, or parts of the source codes, must retain the above copyright notice, this list of conditions
31* and the following disclaimer and requires written permission from the Michael Thomas Flanagan:
32*
33* Redistribution in binary form of all or parts of this class must reproduce the above copyright notice, this list of conditions and
34* the following disclaimer in the documentation and/or other materials provided with the distribution and requires written permission from the Michael Thomas Flanagan:
35*
36* Dr Michael Thomas Flanagan makes no representations about the suitability or fitness of the software for any or for a particular purpose.
37* Dr Michael Thomas Flanagan shall not be liable for any damages suffered as a result of using, modifying or distributing this software
38* or its derivatives.
39*
40***************************************************************************************/
41
42package agents.anac.y2015.agentBuyogV2.flanagan.roots;
43
44import java.util.*;
45
46import agents.anac.y2015.agentBuyogV2.flanagan.complex.Complex;
47import agents.anac.y2015.agentBuyogV2.flanagan.complex.ComplexPoly;
48import agents.anac.y2015.agentBuyogV2.flanagan.math.Fmath;
49
50
51// RealRoot class
52public class RealRoot{
53
54 // INSTANCE VARIABLES
55
56 private double root = Double.NaN; // root to be found
57 private double tol = 1e-9; // tolerance in determining convergence upon a root
58 private int iterMax = 3000; // maximum number of iterations allowed in root search
59 private int iterN = 0; // number of iterations taken in root search
60 private double upperBound = 0; // upper bound for bisection and false position methods
61 private double lowerBound = 0; // lower bound for bisection and false position methods
62 private double estimate = 0; // estimate for Newton-Raphson method
63 private int maximumBoundsExtension = 100; // number of times that the bounds may be extended
64 // by the difference separating them if the root is
65 // found not to be bounded
66 private boolean noBoundExtensions = false; // = true if number of no extension to the bounds allowed
67 private boolean noLowerBoundExtensions = false; // = true if number of no extension to the lower bound allowed
68 private boolean noUpperBoundExtensions = false; // = true if number of no extension to the upper bound allowed
69 private boolean supressLimitReachedMessage = false; // if true, supresses printing of the iteration limit reached message
70 private boolean returnNaN = false; // if true exceptions resulting from a bound being NaN do not halt the prorgam but return NaN
71 // required by PsRandom and Stat classes calling RealRoot
72 private boolean supressNaNmessage = false; // if = true the bound is NaN root returned as NaN message supressed
73
74 // STATC VARIABLE
75
76 private static int staticIterMax = 3000; // maximum number of iterations allowed in root search (static methods)
77
78 private static int maximumStaticBoundsExtension = 100; // number of times that the bounds may be extended
79 // by the difference separating them if the root is
80 // found not to be bounded (static methods)
81 private static boolean noStaticBoundExtensions = false; // = true if number of no extension to the bounds allowed (static methods)
82 private static boolean noStaticLowerBoundExtensions = false;// = true if number of no extension to the lower bound allowed (static methods)
83 private static boolean noStaticUpperBoundExtensions = false;// = true if number of no extension to the upper bound allowed (static methods)
84 private static boolean staticReturnNaN = false; // if true exceptions resulting from a bound being NaN do not halt the prorgam but return NaN
85 // required by PsRandom and Stat classes calling RealRoot (static methods)
86 private static double realTol = 1e-14; // tolerance as imag/real in deciding whether a root is real
87
88 // CONSTRUCTOR
89 public RealRoot(){
90 }
91
92 // INSTANCE METHODS
93
94 // Set lower bound
95 public void setLowerBound(double lower){
96 this.lowerBound = lower;
97 }
98
99 // Set lower bound
100 public void setUpperBound(double upper){
101 this.upperBound = upper;
102 }
103
104 // Reset exception handling for NaN bound flag to true
105 // when flag returnNaN = true exceptions resulting from a bound being NaN do not halt the prorgam but return NaN
106 // required by PsRandom and Stat classes calling RealRoot
107 public void resetNaNexceptionToTrue(){
108 this.returnNaN = true;
109 }
110
111 // Reset exception handling for NaN bound flag to false
112 // when flag returnNaN = false exceptions resulting from a bound being NaN halts the prorgam
113 // required by PsRandom and Stat classes calling RealRoot
114 public void resetNaNexceptionToFalse(){
115 this.returnNaN = false;
116 }
117
118 // Supress NaN bound message
119 // if supressNaNmessage = true the bound is NaN root returned as NaN message supressed
120 public void supressNaNmessage(){
121 this.supressNaNmessage = true;
122 }
123
124 // Allow NaN bound message
125 // if supressNaNmessage = false the bound is NaN root returned as NaN message is written
126 public void allowNaNmessage(){
127 this.supressNaNmessage = false;
128 }
129
130 // Set estimate
131 public void setEstimate(double estimate){
132 this.estimate = estimate;
133 }
134
135 // Reset the default tolerance
136 public void setTolerance(double tolerance){
137 this.tol=tolerance;
138 }
139
140 // Get the default tolerance
141 public double getTolerance(){
142 return this.tol;
143 }
144
145 // Reset the maximum iterations allowed
146 public void setIterMax(int imax){
147 this.iterMax=imax;
148 }
149
150 // Get the maximum iterations allowed
151 public int getIterMax(){
152 return this.iterMax;
153 }
154
155 // Get the number of iterations taken
156 public int getIterN(){
157 return this.iterN;
158 }
159
160 // Reset the maximum number of bounds extensions
161 public void setmaximumStaticBoundsExtension(int maximumBoundsExtension){
162 this.maximumBoundsExtension=maximumBoundsExtension;
163 }
164
165 // Prevent extensions to the supplied bounds
166 public void noBoundsExtensions(){
167 this.noBoundExtensions = true;
168 this.noLowerBoundExtensions = true;
169 this.noUpperBoundExtensions = true;
170 }
171
172 // Prevent extension to the lower bound
173 public void noLowerBoundExtension(){
174 this.noLowerBoundExtensions = true;
175 if(this.noUpperBoundExtensions)this.noBoundExtensions = true;
176 }
177
178 // Prevent extension to the upper bound
179 public void noUpperBoundExtension(){
180 this.noUpperBoundExtensions = true;
181 if(this.noLowerBoundExtensions)this.noBoundExtensions = true;
182 }
183
184 // Supresses printing of the iteration limit reached message
185 // USE WITH CARE - added only to accomadate a specific application using this class!!!!!
186 public void supressLimitReachedMessage(){
187 this.supressLimitReachedMessage = true;
188 }
189
190 // Combined bisection and Inverse Quadratic Interpolation method
191 // bounds already entered
192 public double brent(RealRootFunction g){
193 return this.brent(g, this.lowerBound, this.upperBound);
194 }
195
196 // Combined bisection and Inverse Quadratic Interpolation method
197 // bounds supplied as arguments
198 public double brent(RealRootFunction g, double lower, double upper){
199 this.lowerBound = lower;
200 this.upperBound = upper;
201
202 // check upper>lower
203 if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower");
204
205 boolean testConv = true; // convergence test: becomes false on convergence
206 this.iterN = 0;
207 double temp = 0.0D;
208
209 if(upper<lower){
210 temp = upper;
211 upper = lower;
212 lower = temp;
213 }
214
215 // calculate the function value at the estimate of the higher bound to x
216 double fu = g.function(upper);
217 // calculate the function value at the estimate of the lower bound of x
218 double fl = g.function(lower);
219 if(Double.isNaN(fl)){
220 if(this.returnNaN){
221 if(!this.supressNaNmessage)System.out.println("Realroot: brent: lower bound returned NaN as the function value - NaN returned as root");
222 return Double.NaN;
223 }
224 else{
225 throw new ArithmeticException("lower bound returned NaN as the function value");
226 }
227 }
228 if(Double.isNaN(fu)){
229 if(this.returnNaN){
230 if(!this.supressNaNmessage)System.out.println("Realroot: brent: upper bound returned NaN as the function value - NaN returned as root");
231 return Double.NaN;
232 }
233 else{
234 throw new ArithmeticException("upper bound returned NaN as the function value");
235 }
236 }
237
238 // check that the root has been bounded and extend bounds if not and extension allowed
239 boolean testBounds = true;
240 int numberOfBoundsExtension = 0;
241 double initialBoundsDifference = (upper - lower)/2.0D;
242 while(testBounds){
243 if(fu*fl<=0.0D){
244 testBounds=false;
245 }
246 else{
247 if(this.noBoundExtensions){
248 String message = "RealRoot.brent: root not bounded and no extension to bounds allowed\n";
249 message += "NaN returned";
250 if(!this.supressNaNmessage)System.out.println(message);
251 return Double.NaN;
252 }
253 else{
254 numberOfBoundsExtension++;
255 if(numberOfBoundsExtension>this.maximumBoundsExtension){
256 String message = "RealRoot.brent: root not bounded and maximum number of extension to bounds allowed, " + this.maximumBoundsExtension + ", exceeded\n";
257 message += "NaN returned";
258 if(!this.supressNaNmessage)System.out.println(message);
259 return Double.NaN;
260 }
261 if(!this.noLowerBoundExtensions){
262 lower -= initialBoundsDifference;
263 fl = g.function(lower);
264 }
265 if(!this.noUpperBoundExtensions){
266 upper += initialBoundsDifference;
267 fu = g.function(upper);
268 }
269 }
270 }
271 }
272
273 // check initial values for true root value
274 if(fl==0.0D){
275 this.root=lower;
276 testConv = false;
277 }
278 if(fu==0.0D){
279 this.root=upper;
280 testConv = false;
281 }
282
283 // Function at mid-point of initial estimates
284 double mid=(lower+upper)/2.0D; // mid point (bisect) or new x estimate (Inverse Quadratic Interpolation)
285 double lastMidB = mid; // last succesful mid point
286 double fm = g.function(mid);
287 double diff = mid-lower; // difference between successive estimates of the root
288 double fmB = fm; // last succesful mid value function value
289 double lastMid=mid;
290 boolean lastMethod = true; // true; last method = Inverse Quadratic Interpolation, false; last method = bisection method
291 boolean nextMethod = true; // true; next method = Inverse Quadratic Interpolation, false; next method = bisection method
292
293 // search
294 double rr=0.0D, ss=0.0D, tt=0.0D, pp=0.0D, qq=0.0D; // interpolation variables
295 while(testConv){
296 // test for convergence
297 if(fm==0.0D || Math.abs(diff)<this.tol){
298 testConv=false;
299 if(fm==0.0D){
300 this.root=lastMid;
301 }
302 else{
303 if(Math.abs(diff)<this.tol)this.root=mid;
304 }
305 }
306 else{
307 lastMethod=nextMethod;
308 // test for succesfull inverse quadratic interpolation
309 if(lastMethod){
310 if(mid<lower || mid>upper){
311 // inverse quadratic interpolation failed
312 nextMethod=false;
313 }
314 else{
315 fmB=fm;
316 lastMidB=mid;
317 }
318 }
319 else{
320 nextMethod=true;
321 }
322 if(nextMethod){
323 // inverse quadratic interpolation
324 fl=g.function(lower);
325 fm=g.function(mid);
326 fu=g.function(upper);
327 rr=fm/fu;
328 ss=fm/fl;
329 tt=fl/fu;
330 pp=ss*(tt*(rr-tt)*(upper-mid)-(1.0D-rr)*(mid-lower));
331 qq=(tt-1.0D)*(rr-1.0D)*(ss-1.0D);
332 lastMid=mid;
333 diff=pp/qq;
334 mid=mid+diff;
335 }
336 else{
337 // Bisection procedure
338 fm=fmB;
339 mid=lastMidB;
340 if(fm*fl>0.0D){
341 lower=mid;
342 fl=fm;
343 }
344 else{
345 upper=mid;
346 fu=fm;
347 }
348 lastMid=mid;
349 mid=(lower+upper)/2.0D;
350 fm=g.function(mid);
351 diff=mid-lastMid;
352 fmB=fm;
353 lastMidB=mid;
354 }
355 }
356 this.iterN++;
357 if(this.iterN>this.iterMax){
358 if(!this.supressLimitReachedMessage){
359 if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: brent; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned");
360 if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol);
361 }
362 this.root = mid;
363 testConv = false;
364 }
365 }
366 return this.root;
367 }
368
369 // bisection method
370 // bounds already entered
371 public double bisect(RealRootFunction g){
372 return this.bisect(g, this.lowerBound, this.upperBound);
373 }
374
375 // bisection method
376 public double bisect(RealRootFunction g, double lower, double upper){
377 this.lowerBound = lower;
378 this.upperBound = upper;
379
380 // check upper>lower
381 if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower");
382 if(upper<lower){
383 double temp = upper;
384 upper = lower;
385 lower = temp;
386 }
387
388 boolean testConv = true; // convergence test: becomes false on convergence
389 this.iterN = 0; // number of iterations
390 double diff = 1e300; // abs(difference between the last two successive mid-pint x values)
391
392 // calculate the function value at the estimate of the higher bound to x
393 double fu = g.function(upper);
394 // calculate the function value at the estimate of the lower bound of x
395 double fl = g.function(lower);
396 if(Double.isNaN(fl)){
397 if(this.returnNaN){
398 if(!this.supressNaNmessage)System.out.println("RealRoot: bisect: lower bound returned NaN as the function value - NaN returned as root");
399 return Double.NaN;
400 }
401 else{
402 throw new ArithmeticException("lower bound returned NaN as the function value");
403 }
404 }
405 if(Double.isNaN(fu)){
406 if(this.returnNaN){
407 if(!this.supressNaNmessage)System.out.println("RealRoot: bisect: upper bound returned NaN as the function value - NaN returned as root");
408 return Double.NaN;
409 }
410 else{
411 throw new ArithmeticException("upper bound returned NaN as the function value");
412 }
413 }
414 // check that the root has been bounded and extend bounds if not and extension allowed
415 boolean testBounds = true;
416 int numberOfBoundsExtension = 0;
417 double initialBoundsDifference = (upper - lower)/2.0D;
418 while(testBounds){
419 if(fu*fl<=0.0D){
420 testBounds=false;
421 }
422 else{
423 if(this.noBoundExtensions){
424 String message = "RealRoot.bisect: root not bounded and no extension to bounds allowed\n";
425 message += "NaN returned";
426 if(!this.supressNaNmessage)System.out.println(message);
427 return Double.NaN;
428
429 }
430 else{
431 numberOfBoundsExtension++;
432 if(numberOfBoundsExtension>this.maximumBoundsExtension){
433 String message = "RealRoot.bisect: root not bounded and maximum number of extension to bounds allowed, " + this.maximumBoundsExtension + ", exceeded\n";
434 message += "NaN returned";
435 if(!this.supressNaNmessage)System.out.println(message);
436 return Double.NaN;
437 }
438 if(!this.noLowerBoundExtensions){
439 lower -= initialBoundsDifference;
440 fl = g.function(lower);
441 }
442 if(!this.noUpperBoundExtensions){
443 upper += initialBoundsDifference;
444 fu = g.function(upper);
445 }
446 }
447 }
448 }
449
450 // check initial values for true root value
451 if(fl==0.0D){
452 this.root=lower;
453 testConv = false;
454 }
455 if(fu==0.0D){
456 this.root=upper;
457 testConv = false;
458 }
459
460 // start search
461 double mid = (lower+upper)/2.0D; // mid-point
462 double lastMid = 1e300; // previous mid-point
463 double fm = g.function(mid);
464 while(testConv){
465 if(fm==0.0D || diff<this.tol){
466 testConv=false;
467 this.root=mid;
468 }
469 if(fm*fl>0.0D){
470 lower = mid;
471 fl=fm;
472 }
473 else{
474 upper = mid;
475 fu=fm;
476 }
477 lastMid = mid;
478 mid = (lower+upper)/2.0D;
479 fm = g.function(mid);
480 diff = Math.abs(mid-lastMid);
481 this.iterN++;
482 if(this.iterN>this.iterMax){
483 if(!this.supressLimitReachedMessage){
484 if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: bisect; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned");
485 if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol);
486 }
487 this.root = mid;
488 testConv = false;
489 }
490 }
491 return this.root;
492 }
493
494 // false position method
495 // bounds already entered
496 public double falsePosition(RealRootFunction g){
497 return this.falsePosition(g, this.lowerBound, this.upperBound);
498 }
499
500 // false position method
501 public double falsePosition(RealRootFunction g, double lower, double upper){
502 this.lowerBound = lower;
503 this.upperBound = upper;
504
505 // check upper>lower
506 if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower");
507 if(upper<lower){
508 double temp = upper;
509 upper = lower;
510 lower = temp;
511 }
512
513 boolean testConv = true; // convergence test: becomes false on convergence
514 this.iterN = 0; // number of iterations
515 double diff = 1e300; // abs(difference between the last two successive mid-pint x values)
516
517 // calculate the function value at the estimate of the higher bound to x
518 double fu = g.function(upper);
519 // calculate the function value at the estimate of the lower bound of x
520 double fl = g.function(lower);
521 if(Double.isNaN(fl)){
522 if(this.returnNaN){
523 if(!this.supressNaNmessage)System.out.println("RealRoot: fals: ePositionlower bound returned NaN as the function value - NaN returned as root");
524 return Double.NaN;
525 }
526 else{
527 throw new ArithmeticException("lower bound returned NaN as the function value");
528 }
529 }
530 if(Double.isNaN(fu)){
531 if(this.returnNaN){
532 if(!this.supressNaNmessage)System.out.println("RealRoot: falsePosition: upper bound returned NaN as the function value - NaN returned as root");
533 return Double.NaN;
534 }
535 else{
536 throw new ArithmeticException("upper bound returned NaN as the function value");
537 }
538 }
539
540 // check that the root has been bounded and extend bounds if not and extension allowed
541 boolean testBounds = true;
542 int numberOfBoundsExtension = 0;
543 double initialBoundsDifference = (upper - lower)/2.0D;
544 while(testBounds){
545 if(fu*fl<=0.0D){
546 testBounds=false;
547 }
548 else{
549 if(this.noBoundExtensions){
550 String message = "RealRoot.falsePosition: root not bounded and no extension to bounds allowed\n";
551 message += "NaN returned";
552 if(!this.supressNaNmessage)System.out.println(message);
553 return Double.NaN;
554 }
555 else{
556 numberOfBoundsExtension++;
557 if(numberOfBoundsExtension>this.maximumBoundsExtension){
558 String message = "RealRoot.falsePosition: root not bounded and maximum number of extension to bounds allowed, " + this.maximumBoundsExtension + ", exceeded\n";
559 message += "NaN returned";
560 if(!this.supressNaNmessage)System.out.println(message);
561 return Double.NaN;
562 }
563 if(!this.noLowerBoundExtensions){
564 lower -= initialBoundsDifference;
565 fl = g.function(lower);
566 }
567 if(!this.noUpperBoundExtensions){
568 upper += initialBoundsDifference;
569 fu = g.function(upper);
570 }
571 }
572 }
573 }
574
575 // check initial values for true root value
576 if(fl==0.0D){
577 this.root=lower;
578 testConv = false;
579 }
580 if(fu==0.0D){
581 this.root=upper;
582 testConv = false;
583 }
584
585 // start search
586 double mid = lower+(upper-lower)*Math.abs(fl)/(Math.abs(fl)+Math.abs(fu)); // mid-point
587 double lastMid = 1e300; // previous mid-point
588 double fm = g.function(mid);
589 while(testConv){
590 if(fm==0.0D || diff<this.tol){
591 testConv=false;
592 this.root=mid;
593 }
594 if(fm*fl>0.0D){
595 lower = mid;
596 fl=fm;
597 }
598 else{
599 upper = mid;
600 fu=fm;
601 }
602 lastMid = mid;
603 mid = lower+(upper-lower)*Math.abs(fl)/(Math.abs(fl)+Math.abs(fu)); // mid-point
604 fm = g.function(mid);
605 diff = Math.abs(mid-lastMid);
606 this.iterN++;
607 if(this.iterN>this.iterMax){
608 if(!this.supressLimitReachedMessage){
609 if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: falsePostion; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned");
610 if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol);
611 }
612 this.root = mid;
613 testConv = false;
614 }
615 }
616 return this.root;
617 }
618
619 // Combined bisection and Newton Raphson method
620 // bounds already entered
621 public double bisectNewtonRaphson(RealRootDerivFunction g){
622 return this.bisectNewtonRaphson(g, this.lowerBound, this.upperBound);
623 }
624
625 // Combined bisection and Newton Raphson method
626 // default accuracy used
627 public double bisectNewtonRaphson(RealRootDerivFunction g, double lower, double upper){
628 this.lowerBound = lower;
629 this.upperBound = upper;
630
631 // check upper>lower
632 if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower");
633
634 boolean testConv = true; // convergence test: becomes false on convergence
635 this.iterN = 0; // number of iterations
636 double temp = 0.0D;
637
638 if(upper<lower){
639 temp = upper;
640 upper = lower;
641 lower = temp;
642 }
643
644 // calculate the function value at the estimate of the higher bound to x
645 double[] f = g.function(upper);
646 double fu=f[0];
647 // calculate the function value at the estimate of the lower bound of x
648 f = g.function(lower);
649 double fl=f[0];
650 if(Double.isNaN(fl)){
651 if(this.returnNaN){
652 if(!this.supressNaNmessage)System.out.println("RealRoot: bisectNewtonRaphson: lower bound returned NaN as the function value - NaN returned as root");
653 return Double.NaN;
654 }
655 else{
656 throw new ArithmeticException("lower bound returned NaN as the function value");
657 }
658 }
659 if(Double.isNaN(fu)){
660 if(this.returnNaN){
661 if(!this.supressNaNmessage)System.out.println("RealRoot: bisectNewtonRaphson: upper bound returned NaN as the function value - NaN returned as root");
662 return Double.NaN;
663 }
664 else{
665 throw new ArithmeticException("upper bound returned NaN as the function value");
666 }
667 }
668
669 // check that the root has been bounded and extend bounds if not and extension allowed
670 boolean testBounds = true;
671 int numberOfBoundsExtension = 0;
672 double initialBoundsDifference = (upper - lower)/2.0D;
673 while(testBounds){
674 if(fu*fl<=0.0D){
675 testBounds=false;
676 }
677 else{
678 if(this.noBoundExtensions){
679 String message = "RealRoot.bisectNewtonRaphson: root not bounded and no extension to bounds allowed\n";
680 message += "NaN returned";
681 if(!this.supressNaNmessage)System.out.println(message);
682 return Double.NaN;
683 }
684 else{
685 numberOfBoundsExtension++;
686 if(numberOfBoundsExtension>this.maximumBoundsExtension){
687 String message = "RealRoot.bisectNewtonRaphson: root not bounded and maximum number of extension to bounds allowed, " + this.maximumBoundsExtension + ", exceeded\n";
688 message += "NaN returned";
689 if(!this.supressNaNmessage)System.out.println(message);
690 return Double.NaN;
691 }
692 if(!this.noLowerBoundExtensions){
693 lower -= initialBoundsDifference;
694 f = g.function(lower);
695 fl = f[0];
696 }
697 if(!this.noUpperBoundExtensions){
698 upper += initialBoundsDifference;
699 f = g.function(upper);
700 fu = f[0];
701 }
702 }
703 }
704 }
705
706 // check initial values for true root value
707 if(fl==0.0D){
708 this.root=lower;
709 testConv = false;
710 }
711 if(fu==0.0D){
712 this.root=upper;
713 testConv = false;
714 }
715
716 // Function at mid-point of initial estimates
717 double mid=(lower+upper)/2.0D; // mid point (bisect) or new x estimate (Newton-Raphson)
718 double lastMidB = mid; // last succesful mid point
719 f = g.function(mid);
720 double diff = f[0]/f[1]; // difference between successive estimates of the root
721 double fm = f[0];
722 double fmB = fm; // last succesful mid value function value
723 double lastMid=mid;
724 mid = mid-diff;
725 boolean lastMethod = true; // true; last method = Newton Raphson, false; last method = bisection method
726 boolean nextMethod = true; // true; next method = Newton Raphson, false; next method = bisection method
727
728 // search
729 while(testConv){
730 // test for convergence
731 if(fm==0.0D || Math.abs(diff)<this.tol){
732 testConv=false;
733 if(fm==0.0D){
734 this.root=lastMid;
735 }
736 else{
737 if(Math.abs(diff)<this.tol)this.root=mid;
738 }
739 }
740 else{
741 lastMethod=nextMethod;
742 // test for succesfull Newton-Raphson
743 if(lastMethod){
744 if(mid<lower || mid>upper){
745 // Newton Raphson failed
746 nextMethod=false;
747 }
748 else{
749 fmB=fm;
750 lastMidB=mid;
751 }
752 }
753 else{
754 nextMethod=true;
755 }
756 if(nextMethod){
757 // Newton-Raphson procedure
758 f=g.function(mid);
759 fm=f[0];
760 diff=f[0]/f[1];
761 lastMid=mid;
762 mid=mid-diff;
763 }
764 else{
765 // Bisection procedure
766 fm=fmB;
767 mid=lastMidB;
768 if(fm*fl>0.0D){
769 lower=mid;
770 fl=fm;
771 }
772 else{
773 upper=mid;
774 fu=fm;
775 }
776 lastMid=mid;
777 mid=(lower+upper)/2.0D;
778 f=g.function(mid);
779 fm=f[0];
780 diff=mid-lastMid;
781 fmB=fm;
782 lastMidB=mid;
783 }
784 }
785 this.iterN++;
786 if(this.iterN>this.iterMax){
787 if(!this.supressLimitReachedMessage){
788 if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: bisectNewtonRaphson; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned");
789 if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol);
790 }
791 this.root = mid;
792 testConv = false;
793 }
794 }
795 return this.root;
796 }
797
798 // Newton Raphson method
799 // estimate already entered
800 public double newtonRaphson(RealRootDerivFunction g){
801 return this.newtonRaphson(g, this.estimate);
802
803 }
804
805 // Newton Raphson method
806 public double newtonRaphson(RealRootDerivFunction g, double x){
807 this.estimate = x;
808 boolean testConv = true; // convergence test: becomes false on convergence
809 this.iterN = 0; // number of iterations
810 double diff = 1e300; // difference between the last two successive mid-pint x values
811
812 // calculate the function and derivative value at the initial estimate x
813 double[] f = g.function(x);
814 if(Double.isNaN(f[0])){
815 if(this.returnNaN){
816 if(!this.supressNaNmessage)System.out.println("RealRoot: newtonRaphson: NaN returned as the function value - NaN returned as root");
817 return Double.NaN;
818 }
819 else{
820 throw new ArithmeticException("NaN returned as the function value");
821 }
822 }
823 if(Double.isNaN(f[1])){
824 if(this.returnNaN){
825 if(!this.supressNaNmessage)System.out.println("RealRoot: newtonRaphson: NaN returned as the derivative function value - NaN returned as root");
826 return Double.NaN;
827 }
828 else{
829 throw new ArithmeticException("NaN returned as the derivative function value");
830 }
831 }
832
833
834 // search
835 while(testConv){
836 diff = f[0]/f[1];
837 if(f[0]==0.0D || Math.abs(diff)<this.tol){
838 this.root = x;
839 testConv=false;
840 }
841 else{
842 x -= diff;
843 f = g.function(x);
844 if(Double.isNaN(f[0]))throw new ArithmeticException("NaN returned as the function value");
845 if(Double.isNaN(f[1]))throw new ArithmeticException("NaN returned as the derivative function value");
846 if(Double.isNaN(f[0])){
847 if(this.returnNaN){
848 if(!this.supressNaNmessage)System.out.println("RealRoot: bisect: NaN as the function value - NaN returned as root");
849 return Double.NaN;
850 }
851 else{
852 throw new ArithmeticException("NaN as the function value");
853 }
854 }
855 if(Double.isNaN(f[1])){
856 if(this.returnNaN){
857 if(!this.supressNaNmessage)System.out.println("NaN as the function value - NaN returned as root");
858 return Double.NaN;
859 }
860 else{
861 throw new ArithmeticException("NaN as the function value");
862 }
863 }
864 }
865 this.iterN++;
866 if(this.iterN>this.iterMax){
867 if(!this.supressLimitReachedMessage){
868 if(!this.supressNaNmessage)System.out.println("Class: RealRoot; method: newtonRaphson; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(x, 4) + ", returned");
869 if(!this.supressNaNmessage)System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + this.tol);
870 }
871 this.root = x;
872 testConv = false;
873 }
874 }
875 return this.root;
876 }
877
878 // STATIC METHODS
879
880 // Reset the maximum iterations allowed for static methods
881 public void setStaticIterMax(int imax){
882 RealRoot.staticIterMax = imax;
883 }
884
885 // Get the maximum iterations allowed for static methods
886 public int getStaticIterMax(){
887 return RealRoot.staticIterMax;
888 }
889
890 // Reset the maximum number of bounds extensions for static methods
891 public void setStaticMaximumStaticBoundsExtension(int maximumBoundsExtension){
892 RealRoot.maximumStaticBoundsExtension = maximumBoundsExtension;
893 }
894
895 // Prevent extensions to the supplied bounds for static methods
896 public void noStaticBoundsExtensions(){
897 RealRoot.noStaticBoundExtensions = true;
898 RealRoot.noStaticLowerBoundExtensions = true;
899 RealRoot.noStaticUpperBoundExtensions = true;
900 }
901
902 // Prevent extension to the lower bound for static methods
903 public void noStaticLowerBoundExtension(){
904 RealRoot.noStaticLowerBoundExtensions = true;
905 if(RealRoot.noStaticUpperBoundExtensions)RealRoot.noStaticBoundExtensions = true;
906 }
907
908 // Prevent extension to the upper bound for static methods
909 public void noStaticUpperBoundExtension(){
910 RealRoot.noStaticUpperBoundExtensions = true;
911 if(RealRoot.noStaticLowerBoundExtensions)RealRoot.noStaticBoundExtensions = true;
912 }
913
914 // Reset exception handling for NaN bound flag to true for static methods
915 // when flag returnNaN = true exceptions resulting from a bound being NaN do not halt the prorgam but return NaN
916 // required by PsRandom and Stat classes calling RealRoot
917 public void resetStaticNaNexceptionToTrue(){
918 this.staticReturnNaN = true;
919 }
920
921 // Reset exception handling for NaN bound flag to false for static methods
922 // when flag returnNaN = false exceptions resulting from a bound being NaN halts the prorgam
923 // required by PsRandom and Stat classes calling RealRoot
924 public void resetStaticNaNexceptionToFalse(){
925 this.staticReturnNaN= false;
926 }
927
928
929
930
931 // Combined bisection and Inverse Quadratic Interpolation method
932 // bounds supplied as arguments
933 public static double brent(RealRootFunction g, double lower, double upper, double tol){
934 // check upper>lower
935 if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower");
936
937 double root = Double.NaN;
938 boolean testConv = true; // convergence test: becomes false on convergence
939 int iterN = 0;
940 double temp = 0.0D;
941
942 if(upper<lower){
943 temp = upper;
944 upper = lower;
945 lower = temp;
946 }
947
948 // calculate the function value at the estimate of the higher bound to x
949 double fu = g.function(upper);
950 // calculate the function value at the estimate of the lower bound of x
951 double fl = g.function(lower);
952 if(Double.isNaN(fl)){
953 if(RealRoot.staticReturnNaN){
954 System.out.println("Realroot: brent: lower bound returned NaN as the function value - NaN returned as root");
955 return Double.NaN;
956 }
957 else{
958 throw new ArithmeticException("lower bound returned NaN as the function value");
959 }
960 }
961 if(Double.isNaN(fu)){
962 if(RealRoot.staticReturnNaN){
963 System.out.println("Realroot: brent: upper bound returned NaN as the function value - NaN returned as root");
964 return Double.NaN;
965 }
966 else{
967 throw new ArithmeticException("upper bound returned NaN as the function value");
968 }
969 }
970
971 // check that the root has been bounded and extend bounds if not and extension allowed
972 boolean testBounds = true;
973 int numberOfBoundsExtension = 0;
974 double initialBoundsDifference = (upper - lower)/2.0D;
975 while(testBounds){
976 if(fu*fl<=0.0D){
977 testBounds=false;
978 }
979 else{
980 if(RealRoot.noStaticBoundExtensions){
981 String message = "RealRoot.brent: root not bounded and no extension to bounds allowed\n";
982 message += "NaN returned";
983 System.out.println(message);
984 return Double.NaN;
985 }
986 else{
987 numberOfBoundsExtension++;
988 if(numberOfBoundsExtension>RealRoot.maximumStaticBoundsExtension){
989 String message = "RealRoot.brent: root not bounded and maximum number of extension to bounds allowed, " + RealRoot.maximumStaticBoundsExtension + ", exceeded\n";
990 message += "NaN returned";
991 System.out.println(message);
992 return Double.NaN;
993 }
994 if(!RealRoot.noStaticLowerBoundExtensions){
995 lower -= initialBoundsDifference;
996 fl = g.function(lower);
997 }
998 if(!RealRoot.noStaticUpperBoundExtensions){
999 upper += initialBoundsDifference;
1000 fu = g.function(upper);
1001 }
1002 }
1003 }
1004 }
1005
1006 // check initial values for true root value
1007 if(fl==0.0D){
1008 root=lower;
1009 testConv = false;
1010 }
1011 if(fu==0.0D){
1012 root=upper;
1013 testConv = false;
1014 }
1015
1016 // Function at mid-point of initial estimates
1017 double mid=(lower+upper)/2.0D; // mid point (bisect) or new x estimate (Inverse Quadratic Interpolation)
1018 double lastMidB = mid; // last succesful mid point
1019 double fm = g.function(mid);
1020 double diff = mid-lower; // difference between successive estimates of the root
1021 double fmB = fm; // last succesful mid value function value
1022 double lastMid=mid;
1023 boolean lastMethod = true; // true; last method = Inverse Quadratic Interpolation, false; last method = bisection method
1024 boolean nextMethod = true; // true; next method = Inverse Quadratic Interpolation, false; next method = bisection method
1025
1026 // search
1027 double rr=0.0D, ss=0.0D, tt=0.0D, pp=0.0D, qq=0.0D; // interpolation variables
1028 while(testConv){
1029 // test for convergence
1030 if(fm==0.0D || Math.abs(diff)<tol){
1031 testConv=false;
1032 if(fm==0.0D){
1033 root=lastMid;
1034 }
1035 else{
1036 if(Math.abs(diff)<tol)root=mid;
1037 }
1038 }
1039 else{
1040 lastMethod=nextMethod;
1041 // test for succesfull inverse quadratic interpolation
1042 if(lastMethod){
1043 if(mid<lower || mid>upper){
1044 // inverse quadratic interpolation failed
1045 nextMethod=false;
1046 }
1047 else{
1048 fmB=fm;
1049 lastMidB=mid;
1050 }
1051 }
1052 else{
1053 nextMethod=true;
1054 }
1055 if(nextMethod){
1056 // inverse quadratic interpolation
1057 fl=g.function(lower);
1058 fm=g.function(mid);
1059 fu=g.function(upper);
1060 rr=fm/fu;
1061 ss=fm/fl;
1062 tt=fl/fu;
1063 pp=ss*(tt*(rr-tt)*(upper-mid)-(1.0D-rr)*(mid-lower));
1064 qq=(tt-1.0D)*(rr-1.0D)*(ss-1.0D);
1065 lastMid=mid;
1066 diff=pp/qq;
1067 mid=mid+diff;
1068 }
1069 else{
1070 // Bisection procedure
1071 fm=fmB;
1072 mid=lastMidB;
1073 if(fm*fl>0.0D){
1074 lower=mid;
1075 fl=fm;
1076 }
1077 else{
1078 upper=mid;
1079 fu=fm;
1080 }
1081 lastMid=mid;
1082 mid=(lower+upper)/2.0D;
1083 fm=g.function(mid);
1084 diff=mid-lastMid;
1085 fmB=fm;
1086 lastMidB=mid;
1087 }
1088 }
1089 iterN++;
1090 if(iterN>RealRoot.staticIterMax){
1091 System.out.println("Class: RealRoot; method: brent; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned");
1092 System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol);
1093 root = mid;
1094 testConv = false;
1095 }
1096 }
1097 return root;
1098 }
1099
1100
1101 // bisection method
1102 // tolerance supplied
1103 public static double bisect(RealRootFunction g, double lower, double upper, double tol){
1104
1105 // check upper>lower
1106 if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower");
1107 if(upper<lower){
1108 double temp = upper;
1109 upper = lower;
1110 lower = temp;
1111 }
1112
1113 double root = Double.NaN; // variable to hold the returned root
1114 boolean testConv = true; // convergence test: becomes false on convergence
1115 int iterN = 0; // number of iterations
1116 double diff = 1e300; // abs(difference between the last two successive mid-pint x values)
1117
1118 // calculate the function value at the estimate of the higher bound to x
1119 double fu = g.function(upper);
1120 // calculate the function value at the estimate of the lower bound of x
1121 double fl = g.function(lower);
1122 if(Double.isNaN(fl)){
1123 if(RealRoot.staticReturnNaN){
1124 System.out.println("RealRoot: bisect: lower bound returned NaN as the function value - NaN returned as root");
1125 return Double.NaN;
1126 }
1127 else{
1128 throw new ArithmeticException("lower bound returned NaN as the function value");
1129 }
1130 }
1131 if(Double.isNaN(fu)){
1132 if(RealRoot.staticReturnNaN){
1133 System.out.println("RealRoot: bisect: upper bound returned NaN as the function value - NaN returned as root");
1134 return Double.NaN;
1135 }
1136 else{
1137 throw new ArithmeticException("upper bound returned NaN as the function value");
1138 }
1139 }
1140 // check that the root has been bounded and extend bounds if not and extension allowed
1141 boolean testBounds = true;
1142 int numberOfBoundsExtension = 0;
1143 double initialBoundsDifference = (upper - lower)/2.0D;
1144 while(testBounds){
1145 if(fu*fl<=0.0D){
1146 testBounds = false;
1147 }
1148 else{
1149 if(RealRoot.noStaticBoundExtensions){
1150 String message = "RealRoot.bisect: root not bounded and no extension to bounds allowed\n";
1151 message += "NaN returned";
1152 System.out.println(message);
1153 return Double.NaN;
1154
1155 }
1156 else{
1157 numberOfBoundsExtension++;
1158 if(numberOfBoundsExtension>RealRoot.maximumStaticBoundsExtension){
1159 String message = "RealRoot.bisect: root not bounded and maximum number of extension to bounds allowed, " + RealRoot.maximumStaticBoundsExtension + ", exceeded\n";
1160 message += "NaN returned";
1161 System.out.println(message);
1162 return Double.NaN;
1163 }
1164 if(!RealRoot.noStaticLowerBoundExtensions){
1165 lower -= initialBoundsDifference;
1166 fl = g.function(lower);
1167 }
1168 if(!RealRoot.noStaticUpperBoundExtensions){
1169 upper += initialBoundsDifference;
1170 fu = g.function(upper);
1171 }
1172 }
1173 }
1174 }
1175
1176 // check initial values for true root value
1177 if(fl==0.0D){
1178 root=lower;
1179 testConv = false;
1180 }
1181 if(fu==0.0D){
1182 root=upper;
1183 testConv = false;
1184 }
1185
1186 // start search
1187 double mid = (lower+upper)/2.0D; // mid-point
1188 double lastMid = 1e300; // previous mid-point
1189 double fm = g.function(mid);
1190 while(testConv){
1191 if(fm==0.0D || diff<tol){
1192 testConv=false;
1193 root=mid;
1194 }
1195 if(fm*fl>0.0D){
1196 lower = mid;
1197 fl=fm;
1198 }
1199 else{
1200 upper = mid;
1201 fu=fm;
1202 }
1203 lastMid = mid;
1204 mid = (lower+upper)/2.0D;
1205 fm = g.function(mid);
1206 diff = Math.abs(mid-lastMid);
1207 iterN++;
1208 if(iterN>RealRoot.staticIterMax){
1209 System.out.println("Class: RealRoot; method: bisect; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned");
1210 System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol);
1211 root = mid;
1212 testConv = false;
1213 }
1214 }
1215 return root;
1216 }
1217
1218
1219
1220
1221
1222
1223 // false position method
1224 // tolerance supplied
1225 public static double falsePosition(RealRootFunction g, double lower, double upper, double tol){
1226
1227 // check upper>lower
1228 if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower");
1229 if(upper<lower){
1230 double temp = upper;
1231 upper = lower;
1232 lower = temp;
1233 }
1234
1235 double root = Double.NaN; // variable to hold the returned root
1236 boolean testConv = true; // convergence test: becomes false on convergence
1237 int iterN = 0; // number of iterations
1238 double diff = 1e300; // abs(difference between the last two successive mid-pint x values)
1239
1240 // calculate the function value at the estimate of the higher bound to x
1241 double fu = g.function(upper);
1242 // calculate the function value at the estimate of the lower bound of x
1243 double fl = g.function(lower);
1244 if(Double.isNaN(fl)){
1245 if(RealRoot.staticReturnNaN){
1246 System.out.println("RealRoot: fals: ePositionlower bound returned NaN as the function value - NaN returned as root");
1247 return Double.NaN;
1248 }
1249 else{
1250 throw new ArithmeticException("lower bound returned NaN as the function value");
1251 }
1252 }
1253 if(Double.isNaN(fu)){
1254 if(RealRoot.staticReturnNaN){
1255 System.out.println("RealRoot: falsePosition: upper bound returned NaN as the function value - NaN returned as root");
1256 return Double.NaN;
1257 }
1258 else{
1259 throw new ArithmeticException("upper bound returned NaN as the function value");
1260 }
1261 }
1262
1263 // check that the root has been bounded and extend bounds if not and extension allowed
1264 boolean testBounds = true;
1265 int numberOfBoundsExtension = 0;
1266 double initialBoundsDifference = (upper - lower)/2.0D;
1267 while(testBounds){
1268 if(fu*fl<=0.0D){
1269 testBounds=false;
1270 }
1271 else{
1272 if(RealRoot.noStaticBoundExtensions){
1273 String message = "RealRoot.falsePosition: root not bounded and no extension to bounds allowed\n";
1274 message += "NaN returned";
1275 System.out.println(message);
1276 return Double.NaN;
1277 }
1278 else{
1279 numberOfBoundsExtension++;
1280 if(numberOfBoundsExtension>RealRoot.maximumStaticBoundsExtension){
1281 String message = "RealRoot.falsePosition: root not bounded and maximum number of extension to bounds allowed, " + RealRoot.maximumStaticBoundsExtension + ", exceeded\n";
1282 message += "NaN returned";
1283 System.out.println(message);
1284 return Double.NaN;
1285 }
1286 if(!RealRoot.noStaticLowerBoundExtensions){
1287 lower -= initialBoundsDifference;
1288 fl = g.function(lower);
1289 }
1290 if(!RealRoot.noStaticUpperBoundExtensions){
1291 upper += initialBoundsDifference;
1292 fu = g.function(upper);
1293 }
1294 }
1295 }
1296 }
1297
1298 // check initial values for true root value
1299 if(fl==0.0D){
1300 root=lower;
1301 testConv = false;
1302 }
1303 if(fu==0.0D){
1304 root=upper;
1305 testConv = false;
1306 }
1307
1308 // start search
1309 double mid = lower+(upper-lower)*Math.abs(fl)/(Math.abs(fl)+Math.abs(fu)); // mid-point
1310 double lastMid = 1e300; // previous mid-point
1311 double fm = g.function(mid);
1312 while(testConv){
1313 if(fm==0.0D || diff<tol){
1314 testConv=false;
1315 root=mid;
1316 }
1317 if(fm*fl>0.0D){
1318 lower = mid;
1319 fl=fm;
1320 }
1321 else{
1322 upper = mid;
1323 fu=fm;
1324 }
1325 lastMid = mid;
1326 mid = lower+(upper-lower)*Math.abs(fl)/(Math.abs(fl)+Math.abs(fu)); // mid-point
1327 fm = g.function(mid);
1328 diff = Math.abs(mid-lastMid);
1329 iterN++;
1330 if(iterN>RealRoot.staticIterMax){
1331 System.out.println("Class: RealRoot; method: falsePostion; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned");
1332 System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol);
1333 root = mid;
1334 testConv = false;
1335 }
1336 }
1337 return root;
1338 }
1339
1340
1341
1342
1343
1344
1345 // Combined bisection and Newton Raphson method
1346 // tolerance supplied
1347 public static double bisectNewtonRaphson(RealRootDerivFunction g, double lower, double upper, double tol){
1348
1349 // check upper>lower
1350 if(upper==lower)throw new IllegalArgumentException("upper cannot equal lower");
1351
1352 double root = Double.NaN;
1353 boolean testConv = true; // convergence test: becomes false on convergence
1354 int iterN = 0; // number of iterations
1355 double temp = 0.0D;
1356
1357 if(upper<lower){
1358 temp = upper;
1359 upper = lower;
1360 lower = temp;
1361 }
1362
1363 // calculate the function value at the estimate of the higher bound to x
1364 double[] f = g.function(upper);
1365 double fu=f[0];
1366 // calculate the function value at the estimate of the lower bound of x
1367 f = g.function(lower);
1368 double fl=f[0];
1369 if(Double.isNaN(fl)){
1370 if(RealRoot.staticReturnNaN){
1371 System.out.println("RealRoot: bisectNewtonRaphson: lower bound returned NaN as the function value - NaN returned as root");
1372 return Double.NaN;
1373 }
1374 else{
1375 throw new ArithmeticException("lower bound returned NaN as the function value");
1376 }
1377 }
1378 if(Double.isNaN(fu)){
1379 if(RealRoot.staticReturnNaN){
1380 System.out.println("RealRoot: bisectNewtonRaphson: upper bound returned NaN as the function value - NaN returned as root");
1381 return Double.NaN;
1382 }
1383 else{
1384 throw new ArithmeticException("upper bound returned NaN as the function value");
1385 }
1386 }
1387
1388 // check that the root has been bounded and extend bounds if not and extension allowed
1389 boolean testBounds = true;
1390 int numberOfBoundsExtension = 0;
1391 double initialBoundsDifference = (upper - lower)/2.0D;
1392 while(testBounds){
1393 if(fu*fl<=0.0D){
1394 testBounds=false;
1395 }
1396 else{
1397 if(RealRoot.noStaticBoundExtensions){
1398 String message = "RealRoot.bisectNewtonRaphson: root not bounded and no extension to bounds allowed\n";
1399 message += "NaN returned";
1400 System.out.println(message);
1401 return Double.NaN;
1402 }
1403 else{
1404 numberOfBoundsExtension++;
1405 if(numberOfBoundsExtension>RealRoot.maximumStaticBoundsExtension){
1406 String message = "RealRoot.bisectNewtonRaphson: root not bounded and maximum number of extension to bounds allowed, " + RealRoot.maximumStaticBoundsExtension + ", exceeded\n";
1407 message += "NaN returned";
1408 System.out.println(message);
1409 return Double.NaN;
1410 }
1411 if(!RealRoot.noStaticLowerBoundExtensions){
1412 lower -= initialBoundsDifference;
1413 f = g.function(lower);
1414 fl = f[0];
1415 }
1416 if(!RealRoot.noStaticUpperBoundExtensions){
1417 upper += initialBoundsDifference;
1418 f = g.function(upper);
1419 fu = f[0];
1420 }
1421 }
1422 }
1423 }
1424
1425 // check initial values for true root value
1426 if(fl==0.0D){
1427 root=lower;
1428 testConv = false;
1429 }
1430 if(fu==0.0D){
1431 root=upper;
1432 testConv = false;
1433 }
1434
1435 // Function at mid-point of initial estimates
1436 double mid=(lower+upper)/2.0D; // mid point (bisect) or new x estimate (Newton-Raphson)
1437 double lastMidB = mid; // last succesful mid point
1438 f = g.function(mid);
1439 double diff = f[0]/f[1]; // difference between successive estimates of the root
1440 double fm = f[0];
1441 double fmB = fm; // last succesful mid value function value
1442 double lastMid=mid;
1443 mid = mid-diff;
1444 boolean lastMethod = true; // true; last method = Newton Raphson, false; last method = bisection method
1445 boolean nextMethod = true; // true; next method = Newton Raphson, false; next method = bisection method
1446
1447 // search
1448 while(testConv){
1449 // test for convergence
1450 if(fm==0.0D || Math.abs(diff)<tol){
1451 testConv=false;
1452 if(fm==0.0D){
1453 root=lastMid;
1454 }
1455 else{
1456 if(Math.abs(diff)<tol)root=mid;
1457 }
1458 }
1459 else{
1460 lastMethod=nextMethod;
1461 // test for succesfull Newton-Raphson
1462 if(lastMethod){
1463 if(mid<lower || mid>upper){
1464 // Newton Raphson failed
1465 nextMethod=false;
1466 }
1467 else{
1468 fmB=fm;
1469 lastMidB=mid;
1470 }
1471 }
1472 else{
1473 nextMethod=true;
1474 }
1475 if(nextMethod){
1476 // Newton-Raphson procedure
1477 f=g.function(mid);
1478 fm=f[0];
1479 diff=f[0]/f[1];
1480 lastMid=mid;
1481 mid=mid-diff;
1482 }
1483 else{
1484 // Bisection procedure
1485 fm=fmB;
1486 mid=lastMidB;
1487 if(fm*fl>0.0D){
1488 lower=mid;
1489 fl=fm;
1490 }
1491 else{
1492 upper=mid;
1493 fu=fm;
1494 }
1495 lastMid=mid;
1496 mid=(lower+upper)/2.0D;
1497 f=g.function(mid);
1498 fm=f[0];
1499 diff=mid-lastMid;
1500 fmB=fm;
1501 lastMidB=mid;
1502 }
1503 }
1504 iterN++;
1505 if(iterN>RealRoot.staticIterMax){
1506 System.out.println("Class: RealRoot; method: bisectNewtonRaphson; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(mid, 4) + ", returned");
1507 System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol);
1508 root = mid;
1509 testConv = false;
1510 }
1511 }
1512 return root;
1513 }
1514
1515
1516
1517
1518
1519 // Newton Raphson method
1520 public static double newtonRaphson(RealRootDerivFunction g, double x, double tol){
1521 double root = Double.NaN;
1522 boolean testConv = true; // convergence test: becomes false on convergence
1523 int iterN = 0; // number of iterations
1524 double diff = 1e300; // difference between the last two successive mid-pint x values
1525
1526 // calculate the function and derivative value at the initial estimate x
1527 double[] f = g.function(x);
1528 if(Double.isNaN(f[0])){
1529 if(RealRoot.staticReturnNaN){
1530 System.out.println("RealRoot: newtonRaphson: NaN returned as the function value - NaN returned as root");
1531 return Double.NaN;
1532 }
1533 else{
1534 throw new ArithmeticException("NaN returned as the function value");
1535 }
1536 }
1537 if(Double.isNaN(f[1])){
1538 if(RealRoot.staticReturnNaN){
1539 System.out.println("RealRoot: newtonRaphson: NaN returned as the derivative function value - NaN returned as root");
1540 return Double.NaN;
1541 }
1542 else{
1543 throw new ArithmeticException("NaN returned as the derivative function value");
1544 }
1545 }
1546
1547
1548 // search
1549 while(testConv){
1550 diff = f[0]/f[1];
1551 if(f[0]==0.0D || Math.abs(diff)<tol){
1552 root = x;
1553 testConv=false;
1554 }
1555 else{
1556 x -= diff;
1557 f = g.function(x);
1558 if(Double.isNaN(f[0]))throw new ArithmeticException("NaN returned as the function value");
1559 if(Double.isNaN(f[1]))throw new ArithmeticException("NaN returned as the derivative function value");
1560 if(Double.isNaN(f[0])){
1561 if(RealRoot.staticReturnNaN){
1562 System.out.println("RealRoot: NewtonRaphson: NaN as the function value - NaN returned as root");
1563 return Double.NaN;
1564 }
1565 else{
1566 throw new ArithmeticException("NaN as the function value");
1567 }
1568 }
1569 if(Double.isNaN(f[1])){
1570 if(RealRoot.staticReturnNaN){
1571 System.out.println("NaN as the function value - NaN returned as root");
1572 return Double.NaN;
1573 }
1574 else{
1575 throw new ArithmeticException("NaN as the function value");
1576 }
1577 }
1578 }
1579 iterN++;
1580 if(iterN>RealRoot.staticIterMax){
1581 System.out.println("Class: RealRoot; method: newtonRaphson; maximum number of iterations exceeded - root at this point, " + Fmath.truncate(x, 4) + ", returned");
1582 System.out.println("Last mid-point difference = " + Fmath.truncate(diff, 4) + ", tolerance = " + tol);
1583 root = x;
1584 testConv = false;
1585 }
1586 }
1587 return root;
1588 }
1589
1590 // ROOTS OF A QUADRATIC EQUATION
1591 // c + bx + ax^2 = 0
1592 // roots returned in root[]
1593 // 4ac << b*b accomodated by these methods
1594 // roots returned as Double in an ArrayList if roots are real
1595 // roots returned as Complex in an ArrayList if any root is complex
1596 public static ArrayList<Object> quadratic(double c, double b, double a){
1597
1598 ArrayList<Object> roots = new ArrayList<Object>(2);
1599
1600 double bsquared = b*b;
1601 double fourac = 4.0*a*c;
1602 if(bsquared<fourac){
1603 Complex[] croots = ComplexPoly.quadratic(c, b, a);
1604 roots.add("complex");
1605 roots.add(croots);
1606 }
1607 else{
1608 double[] droots = new double[2];
1609 double bsign = Fmath.sign(b);
1610 double qsqrt = Math.sqrt(bsquared - fourac);
1611 qsqrt = -0.5*(b + bsign*qsqrt);
1612 droots[0] = qsqrt/a;
1613 droots[1] = c/qsqrt;
1614 roots.add("real");
1615 roots.add(droots);
1616 }
1617 return roots;
1618 }
1619
1620
1621 // ROOTS OF A CUBIC EQUATION
1622 // a + bx + cx^2 + dx^3 = 0
1623 // roots returned as Double in an ArrayList if roots are real
1624 // roots returned as Complex in an ArrayList if any root is complex
1625 public static ArrayList<Object> cubic(double a, double b, double c, double d){
1626
1627 ArrayList<Object> roots = new ArrayList<Object>(2);
1628
1629 double aa = c/d;
1630 double bb = b/d;
1631 double cc = a/d;
1632 double bigQ = (aa*aa - 3.0*bb)/9.0;
1633 double bigQcubed = bigQ*bigQ*bigQ;
1634 double bigR = (2.0*aa*aa*aa - 9.0*aa*bb + 27.0*cc)/54.0;
1635 double bigRsquared = bigR*bigR;
1636
1637 if(bigRsquared>=bigQcubed){
1638 Complex[] croots = ComplexPoly.cubic(a, b, c, d);
1639 roots.add("complex");
1640 roots.add(croots);
1641 }
1642 else{
1643 double[] droots = new double[3];
1644 double theta = Math.acos(bigR/Math.sqrt(bigQcubed));
1645 double aover3 = aa/3.0;
1646 double qterm = -2.0*Math.sqrt(bigQ);
1647
1648 droots[0] = qterm*Math.cos(theta/3.0) - aover3;
1649 droots[1] = qterm*Math.cos((theta + 2.0*Math.PI)/3.0) - aover3;
1650 droots[2] = qterm*Math.cos((theta - 2.0*Math.PI)/3.0) - aover3;
1651 roots.add("real");
1652 roots.add(droots);
1653 }
1654 return roots;
1655 }
1656
1657 // ROOTS OF A POLYNOMIAL
1658 // For general details of root searching and a discussion of the rounding errors
1659 // see Numerical Recipes, The Art of Scientific Computing
1660 // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery
1661 // Cambridge University Press, http://www.nr.com/
1662
1663 // Calculate the roots of a real polynomial
1664 // initial root estimate is zero [for deg>3]
1665 // roots are not olished [for deg>3]
1666 public static ArrayList<Object> polynomial(double[] coeff){
1667 boolean polish=true;
1668 double estx = 0.0;
1669 return RealRoot.polynomial(coeff, polish, estx);
1670 }
1671
1672 // Calculate the roots of a real polynomial
1673 // initial root estimate is zero [for deg>3]
1674 // roots are polished [for deg>3]
1675 public static ArrayList<Object> polynomial(double[] coeff, boolean polish){
1676 double estx = 0.0;
1677 return RealRoot.polynomial (coeff, polish, estx);
1678 }
1679
1680 // Calculate the roots of a real polynomial
1681 // initial root estimate is estx [for deg>3]
1682 // roots are not polished [for deg>3]
1683 public static ArrayList<Object> polynomial(double[] coeff, double estx){
1684 boolean polish=true;
1685 return RealRoot.polynomial(coeff, polish, estx);
1686 }
1687
1688 // Calculate the roots of a real polynomial
1689 // initial root estimate is estx [for deg>3]
1690 // roots are polished [for deg>3]
1691 public static ArrayList<Object> polynomial (double[] coeff, boolean polish, double estx){
1692
1693 int nCoeff = coeff.length;
1694 if(nCoeff<2)throw new IllegalArgumentException("a minimum of two coefficients is required");
1695 ArrayList<Object> roots = new ArrayList<Object>(nCoeff);
1696 boolean realRoots = true;
1697
1698 // check for zero roots
1699 int nZeros=0;
1700 int ii=0;
1701 boolean testZero=true;
1702 while(testZero){
1703 if(coeff[ii]==0.0){
1704 nZeros++;
1705 ii++;
1706 }
1707 else{
1708 testZero=false;
1709 }
1710 }
1711
1712 // Repack coefficients
1713 int nCoeffWz = nCoeff - nZeros;
1714 double[] coeffWz = new double[nCoeffWz];
1715 if(nZeros>0){
1716 for(int i=0; i<nCoeffWz; i++)coeffWz[i] = coeff[i+nZeros];
1717 }
1718 else{
1719 for(int i=0; i<nCoeffWz; i++)coeffWz[i] = coeff[i];
1720 }
1721
1722 // Calculate non-zero roots
1723 ArrayList<Object> temp = new ArrayList<Object>(2);
1724 double[] cdreal = null;
1725 switch(nCoeffWz){
1726 case 0:
1727 case 1: break;
1728 case 2: temp.add("real");
1729 double[] dtemp = {-coeffWz[0]/coeffWz[1]};
1730 temp.add(dtemp);
1731 break;
1732 case 3: temp = RealRoot.quadratic(coeffWz[0],coeffWz[1],coeffWz[2]);
1733 if(((String)temp.get(0)).equals("complex"))realRoots = false;
1734 break;
1735 case 4: temp = RealRoot.cubic(coeffWz[0],coeffWz[1],coeffWz[2], coeffWz[3]);
1736 if(((String)temp.get(0)).equals("complex"))realRoots = false;
1737 break;
1738 default: ComplexPoly cp = new ComplexPoly(coeffWz);
1739 Complex[] croots = cp.roots(polish, new Complex(estx, 0.0));
1740 cdreal = new double[nCoeffWz-1];
1741 int counter = 0;
1742 for(int i=0; i<(nCoeffWz-1); i++){
1743 if(croots[i].getImag()/croots[i].getReal()<RealRoot.realTol){
1744 cdreal[i] = croots[i].getReal();
1745 counter++;
1746 }
1747 }
1748 if(counter==(nCoeffWz-1)){
1749 temp.add("real");
1750 temp.add(cdreal);
1751 }
1752 else{
1753 temp.add("complex");
1754 temp.add(croots);
1755 realRoots = false;
1756 }
1757 }
1758
1759 // Pack roots into returned ArrayList
1760 if(nZeros==0){
1761 roots = temp;
1762 }
1763 else{
1764 if(realRoots){
1765 double[] dtemp1 = new double[nCoeff-1];
1766 double[] dtemp2 = (double[])temp.get(1);
1767 for(int i=0; i<nCoeffWz-1; i++)dtemp1[i] = dtemp2[i];
1768 for(int i=0; i<nZeros; i++)dtemp1[i+nCoeffWz-1] = 0.0;
1769 roots.add("real");
1770 roots.add(dtemp1);
1771 }
1772 else{
1773 Complex[] dtemp1 = Complex.oneDarray(nCoeff-1);
1774 Complex[] dtemp2 = (Complex[])temp.get(1);
1775 for(int i=0; i<nCoeffWz-1; i++)dtemp1[i] = dtemp2[i];
1776 for(int i=0; i<nZeros; i++)dtemp1[i+nCoeffWz-1] = new Complex(0.0, 0.0);
1777 roots.add("complex");
1778 roots.add(dtemp1);
1779 }
1780 }
1781
1782 return roots;
1783 }
1784
1785 // Reset the criterion for deciding a that a root, calculated as Complex, is real
1786 // Default option; imag/real <1e-14
1787 // this method allows thew value of 1e-14 to be reset
1788 public void resetRealTest(double ratio){
1789 RealRoot.realTol = ratio;
1790 }
1791
1792}
Note: See TracBrowser for help on using the repository browser.