001/*
002 * $Id$
003 */
004
005package edu.jas.root;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import org.apache.logging.log4j.Logger;
012import org.apache.logging.log4j.LogManager; 
013
014import edu.jas.arith.BigDecimal;
015import edu.jas.arith.BigInteger;
016import edu.jas.arith.BigRational;
017import edu.jas.arith.Rational;
018import edu.jas.arith.Roots;
019import edu.jas.poly.GenPolynomial;
020import edu.jas.poly.GenPolynomialRing;
021import edu.jas.poly.PolyUtil;
022import edu.jas.structure.RingElem;
023import edu.jas.structure.RingFactory;
024import edu.jas.structure.UnaryFunctor;
025
026
027/**
028 * Real roots abstract class.
029 * @param <C> coefficient type.
030 * @author Heinz Kredel
031 */
032public abstract class RealRootsAbstract<C extends RingElem<C> & Rational> implements RealRoots<C> {
033
034
035    private static final Logger logger = LogManager.getLogger(RealRootsAbstract.class);
036
037
038    //private static final boolean debug = logger.isDebugEnabled();
039
040
041    /**
042     * Real root bound. With f(-M) * f(M) != 0.
043     * @param f univariate polynomial.
044     * @return M such that -M &lt; root(f) &lt; M.
045     */
046    public C realRootBound(GenPolynomial<C> f) {
047        if (f == null) {
048            return null;
049        }
050        RingFactory<C> cfac = f.ring.coFac;
051        C M = cfac.getONE();
052        if (f.isZERO()) {
053            return M;
054        }
055        if (f.isConstant()) {
056            M = f.leadingBaseCoefficient().abs().sum(cfac.getONE());
057            return M;
058        }
059        C a = f.leadingBaseCoefficient().abs();
060        for (C c : f.getMap().values()) {
061            C d = c.abs().divide(a);
062            if (M.compareTo(d) < 0) {
063                M = d;
064            }
065        }
066        BigRational r = M.getRational();
067        logger.info("rational root bound: " + r);
068        BigInteger i = new BigInteger(r.numerator().divide(r.denominator()));
069        i = i.sum(BigInteger.ONE); // ceiling
070        M = cfac.fromInteger(i.getVal());
071        M = M.sum(f.ring.coFac.getONE());
072        logger.info("integer root bound: " + M);
073        //System.out.println("M = " + M);
074        return M;
075    }
076
077
078    /**
079     * Magnitude bound.
080     * @param iv interval.
081     * @param f univariate polynomial.
082     * @return B such that |f(c)| &lt; B for c in iv.
083     */
084    @SuppressWarnings("cast")
085    public C magnitudeBound(Interval<C> iv, GenPolynomial<C> f) {
086        if (f == null) {
087            return null;
088        }
089        if (f.isZERO()) {
090            return f.ring.coFac.getONE();
091        }
092        if (f.isConstant()) {
093            return f.leadingBaseCoefficient().abs();
094        }
095        GenPolynomial<C> fa = f.map(new UnaryFunctor<C, C>() {
096
097
098                public C eval(C a) {
099                    return a.abs();
100                }
101            });
102        //System.out.println("fa = " + fa);
103        C M = iv.left.abs();
104        if (M.compareTo(iv.right.abs()) < 0) {
105            M = iv.right.abs();
106        }
107        //System.out.println("M = " + M);
108        RingFactory<C> cfac = f.ring.coFac;
109        C B = PolyUtil.<C> evaluateMain(cfac, fa, M);
110        // works also without this case, only for optimization 
111        // to use rational number interval end points
112        // can fail if real root is in interval [r,r+1] 
113        // for too low precision or too big r, since r is approximation
114        //if ((Object) B instanceof RealAlgebraicNumber) {
115        //    RealAlgebraicNumber Br = (RealAlgebraicNumber) B;
116        //    BigRational r = Br.magnitude();
117        //    B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator()));
118        //}
119        BigRational r = B.getRational();
120        B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator()));
121        //System.out.println("B = " + B);
122        return B;
123    }
124
125
126    /**
127     * Real minimal root bound. 
128     * @param f univariate polynomial.
129     * @return M such that abs(xi) &gt; M for f(xi) == 0.
130     */
131    public C realMinimalRootBound(GenPolynomial<C> f) {
132        if (f == null) {
133            return null;
134        }
135        RingFactory<C> cfac = f.ring.coFac;
136        // maxNorm root bound
137        BigRational mr = f.maxNorm().getRational().sum(BigRational.ONE);
138        BigRational di = mr.sum(BigRational.ONE).inverse();
139        C B = cfac.fromInteger(di.numerator()).divide(cfac.fromInteger(di.denominator()));
140        //System.out.println("B = " + B + ", sign(B) = " + B.signum());
141        return B;
142    }
143
144
145    /**
146     * Real minimal root separation. 
147     * @param f univariate polynomial.
148     * @return M such that abs(xi-xj) &gt; M for roots xi, xj of f.
149     */
150    public C realMinimalRootSeparation(GenPolynomial<C> f) {
151        if (f == null) {
152            return null;
153        }
154        RingFactory<C> cfac = f.ring.coFac;
155        // sumNorm root bound
156        BigRational pr = f.sumNorm().getRational();
157        pr = pr.sum(BigRational.ONE);
158        BigRational sep = BigRational.ZERO;
159        long n = f.degree();
160        if (n > 0) {
161            sep = pr.power(2*n).multiply(pr.fromInteger(n).power(n+1)).inverse();
162        }
163        //System.out.println("sep = " + sep + ", sign(sep) = " + sep.signum());
164        C M = cfac.fromInteger(sep.numerator()).divide(cfac.fromInteger(sep.denominator()));
165        return M;
166    }
167
168
169    /**
170     * Bi-section point.
171     * @param iv interval with f(left) * f(right) != 0.
172     * @param f univariate polynomial, non-zero.
173     * @return a point c in the interval iv such that f(c) != 0.
174     */
175    public C bisectionPoint(Interval<C> iv, GenPolynomial<C> f) {
176        if (f == null) {
177            return null;
178        }
179        RingFactory<C> cfac = f.ring.coFac;
180        C two = cfac.fromInteger(2);
181        C c = iv.left.sum(iv.right);
182        c = c.divide(two);
183        if (f.isZERO() || f.isConstant()) {
184            return c;
185        }
186        C m = PolyUtil.<C> evaluateMain(cfac, f, c);
187        while (m.isZERO()) {
188            C d = iv.left.sum(c);
189            d = d.divide(two);
190            if (d.equals(c)) {
191                d = iv.right.sum(c);
192                d = d.divide(two);
193                if (d.equals(c)) {
194                    throw new RuntimeException("should not happen " + iv);
195                }
196            }
197            c = d;
198            m = PolyUtil.<C> evaluateMain(cfac, f, c);
199            //System.out.println("c = " + c);
200        }
201        //System.out.println("c = " + c);
202        return c;
203    }
204
205
206    /**
207     * Isolating intervals for the real roots.
208     * @param f univariate polynomial.
209     * @return a list of isolating intervalls for the real roots of f.
210     */
211    public abstract List<Interval<C>> realRoots(GenPolynomial<C> f);
212
213
214    /**
215     * Isolating intervals for the real roots.
216     * @param f univariate polynomial.
217     * @param eps requested intervals length.
218     * @return a list of isolating intervals v such that |v| &lt; eps.
219     */
220    public List<Interval<C>> realRoots(GenPolynomial<C> f, C eps) {
221        return realRoots(f, eps.getRational());
222    }
223
224
225    /**
226     * Isolating intervals for the real roots.
227     * @param f univariate polynomial.
228     * @param eps requested intervals length.
229     * @return a list of isolating intervals v such that |v| &lt; eps.
230     */
231    public List<Interval<C>> realRoots(GenPolynomial<C> f, BigRational eps) {
232        List<Interval<C>> iv = realRoots(f);
233        return refineIntervals(iv, f, eps);
234    }
235
236
237    /**
238     * Sign changes on interval bounds.
239     * @param iv root isolating interval with f(left) * f(right) != 0.
240     * @param f univariate polynomial.
241     * @return true if f(left) * f(right) &lt; 0, else false
242     */
243    public boolean signChange(Interval<C> iv, GenPolynomial<C> f) {
244        if (f == null) {
245            return false;
246        }
247        RingFactory<C> cfac = f.ring.coFac;
248        C l = PolyUtil.<C> evaluateMain(cfac, f, iv.left);
249        C r = PolyUtil.<C> evaluateMain(cfac, f, iv.right);
250        return l.signum() * r.signum() < 0;
251    }
252
253
254    /**
255     * Number of real roots in interval.
256     * @param iv interval with f(left) * f(right) != 0.
257     * @param f univariate polynomial.
258     * @return number of real roots of f in I.
259     */
260    public abstract long realRootCount(Interval<C> iv, GenPolynomial<C> f);
261
262
263    /**
264     * Half interval.
265     * @param iv root isolating interval with f(left) * f(right) &lt; 0.
266     * @param f univariate polynomial, non-zero.
267     * @return a new interval v such that |v| &lt; |iv|/2.
268     */
269    public Interval<C> halfInterval(Interval<C> iv, GenPolynomial<C> f) {
270        if (f == null || f.isZERO()) {
271            return iv;
272        }
273        BigRational len = iv.rationalLength();
274        BigRational two = len.factory().fromInteger(2);
275        BigRational eps = len.divide(two);
276        return refineInterval(iv, f, eps);
277    }
278
279
280    /**
281     * Refine interval.
282     * @param iv root isolating interval with f(left) * f(right) &lt; 0.
283     * @param f univariate polynomial, non-zero.
284     * @param eps requested interval length.
285     * @return a new interval v such that |v| &lt; eps.
286     */
287    public Interval<C> refineInterval(Interval<C> iv, GenPolynomial<C> f, BigRational eps) {
288        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
289            return iv;
290        }
291        if (iv.rationalLength().compareTo(eps) < 0) {
292            return iv;
293        }
294        RingFactory<C> cfac = f.ring.coFac;
295        C two = cfac.fromInteger(2);
296        Interval<C> v = iv;
297        while (v.rationalLength().compareTo(eps) >= 0) {
298            C c = v.left.sum(v.right);
299            c = c.divide(two);
300            //System.out.println("c = " + c);
301            //c = RootUtil.<C>bisectionPoint(v,f);
302            if (PolyUtil.<C> evaluateMain(cfac, f, c).isZERO()) {
303                v = new Interval<C>(c, c);
304                break;
305            }
306            Interval<C> iv1 = new Interval<C>(v.left, c);
307            if (signChange(iv1, f)) {
308                v = iv1;
309            } else {
310                v = new Interval<C>(c, v.right);
311            }
312        }
313        return v;
314    }
315
316
317    /**
318     * Refine intervals.
319     * @param V list of isolating intervals with f(left) * f(right) &lt; 0.
320     * @param f univariate polynomial, non-zero.
321     * @param eps requested intervals length.
322     * @return a list of new intervals v such that |v| &lt; eps.
323     */
324    public List<Interval<C>> refineIntervals(List<Interval<C>> V, GenPolynomial<C> f, BigRational eps) {
325        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
326            return V;
327        }
328        List<Interval<C>> IV = new ArrayList<Interval<C>>();
329        for (Interval<C> v : V) {
330            Interval<C> iv = refineInterval(v, f, eps);
331            IV.add(iv);
332        }
333        return IV;
334    }
335
336
337    /**
338     * Invariant interval for algebraic number sign.
339     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0.
340     * @param f univariate polynomial, non-zero.
341     * @param g univariate polynomial, gcd(f,g) == 1.
342     * @return v with v a new interval contained in iv such that g(v) != 0.
343     */
344    public abstract Interval<C> invariantSignInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g);
345
346
347    /**
348     * Real algebraic number sign.
349     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0,
350     *            with iv such that g(iv) != 0.
351     * @param f univariate polynomial, non-zero.
352     * @param g univariate polynomial, gcd(f,g) == 1.
353     * @return sign(g(iv)) .
354     */
355    public int realIntervalSign(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) {
356        if (g == null || g.isZERO()) {
357            return 0;
358        }
359        if (f == null || f.isZERO() || f.isConstant()) {
360            return g.signum();
361        }
362        if (g.isConstant()) {
363            return g.signum();
364        }
365        RingFactory<C> cfac = f.ring.coFac;
366        C c = iv.left.sum(iv.right);
367        c = c.divide(cfac.fromInteger(2));
368        C ev = PolyUtil.<C> evaluateMain(cfac, g, c);
369        //System.out.println("ev = " + ev);
370        return ev.signum();
371    }
372
373
374    /**
375     * Real algebraic number sign.
376     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0.
377     * @param f univariate polynomial, non-zero.
378     * @param g univariate polynomial, gcd(f,g) == 1.
379     * @return sign(g(v)), with v a new interval contained in iv such that g(v)
380     *         != 0.
381     */
382    public int realSign(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) {
383        if (g == null || g.isZERO()) {
384            return 0;
385        }
386        if (f == null || f.isZERO() || f.isConstant()) {
387            return g.signum();
388        }
389        if (g.isConstant()) {
390            return g.signum();
391        }
392        Interval<C> v = invariantSignInterval(iv, f, g);
393        return realIntervalSign(v, f, g);
394    }
395
396
397    /**
398     * Invariant interval for algebraic number magnitude.
399     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0.
400     * @param f univariate polynomial, non-zero.
401     * @param g univariate polynomial, gcd(f,g) == 1.
402     * @param eps length limit for interval length.
403     * @return v with v a new interval contained in iv such that |g(a) - g(b)|
404     *         &lt; eps for a, b in v in iv.
405     */
406    public Interval<C> invariantMagnitudeInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g,
407                                                  BigRational eps) {
408        Interval<C> v = iv;
409        if (g == null || g.isZERO()) {
410            return v;
411        }
412        if (g.isConstant()) {
413            return v;
414        }
415        if (f == null || f.isZERO() || f.isConstant()) { // ?
416            return v;
417        }
418        GenPolynomial<C> gp = PolyUtil.<C> baseDeriviative(g);
419        //System.out.println("g  = " + g);
420        //System.out.println("gp = " + gp);
421        C B = magnitudeBound(iv, gp);
422        //System.out.println("B = " + B);
423        RingFactory<C> cfac = f.ring.coFac;
424        C two = cfac.fromInteger(2);
425        while (B.multiply(v.length()).getRational().compareTo(eps) >= 0) {
426            C c = v.left.sum(v.right);
427            c = c.divide(two);
428            Interval<C> im = new Interval<C>(c, v.right);
429            if (signChange(im, f)) {
430                v = im;
431            } else {
432                v = new Interval<C>(v.left, c);
433            }
434            //System.out.println("v = " + v.toDecimal());
435        }
436        return v;
437    }
438
439
440    /**
441     * Real algebraic number magnitude.
442     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0,
443     *            with iv such that |g(a) - g(b)| &lt; eps for a, b in iv.
444     * @param f univariate polynomial, non-zero.
445     * @param g univariate polynomial, gcd(f,g) == 1.
446     * @return g(iv) .
447     */
448    public C realIntervalMagnitude(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) {
449        if (g.isZERO() || g.isConstant()) {
450            return g.leadingBaseCoefficient();
451        }
452        RingFactory<C> cfac = f.ring.coFac;
453        C evl = PolyUtil.<C> evaluateMain(cfac, g, iv.left);
454        C evr = PolyUtil.<C> evaluateMain(cfac, g, iv.right);
455        C ev = evl;
456        if (evl.compareTo(evr) <= 0) {
457            ev = evr;
458        }
459        //System.out.println("ev = " + ev + ", evl = " + evl + ", evr = " + evr + ", iv = " + iv);
460        return ev;
461    }
462
463
464    /**
465     * Real algebraic number magnitude.
466     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0.
467     * @param f univariate polynomial, non-zero.
468     * @param g univariate polynomial, gcd(f,g) == 1.
469     * @param eps length limit for interval length.
470     * @return g(iv) .
471     */
472    public C realMagnitude(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g, BigRational eps) {
473        if (g.isZERO() || g.isConstant()) {
474            return g.leadingBaseCoefficient();
475        }
476        Interval<C> v = invariantMagnitudeInterval(iv, f, g, eps);
477        return realIntervalMagnitude(v, f, g);
478    }
479
480
481    /**
482     * Real algebraic number magnitude.
483     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0,
484     *            with iv such that |g(a) - g(b)| &lt; eps for a, b in iv.
485     * @param f univariate polynomial, non-zero.
486     * @param g univariate polynomial, gcd(f,g) == 1.
487     * @return Interval( g(iv.left), g(iv.right) ) .
488     */
489    public Interval<C> realIntervalMagnitudeInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) {
490        if (g.isZERO() || g.isConstant()) {
491            return iv;
492        }
493        RingFactory<C> cfac = f.ring.coFac;
494        C evl = PolyUtil.<C> evaluateMain(cfac, g, iv.left);
495        C evr = PolyUtil.<C> evaluateMain(cfac, g, iv.right);
496        Interval<C> ev = new Interval<C>(evr, evl);
497        if (evl.compareTo(evr) <= 0) {
498            ev = new Interval<C>(evl, evr);
499        }
500        System.out.println("ev = " + ev + ", iv = " + iv);
501        return ev;
502    }
503
504
505    /**
506     * Approximate real root.
507     * @param iv real root isolating interval with f(left) * f(right) &lt; 0.
508     * @param f univariate polynomial, non-zero.
509     * @param eps requested interval length.
510     * @return a decimal approximation d such that |d-v| &lt; eps, for f(v) = 0,
511     *         v real.
512     */
513    public BigDecimal approximateRoot(Interval<C> iv, GenPolynomial<C> f, BigRational eps)
514        throws NoConvergenceException {
515        if (iv == null) {
516            throw new IllegalArgumentException("null interval not allowed");
517        }
518        BigDecimal d = iv.toDecimal();
519        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
520            return d;
521        }
522        if (iv.rationalLength().compareTo(eps) < 0) {
523            return d;
524        }
525        BigDecimal left = new BigDecimal(iv.left.getRational());
526        BigDecimal right = new BigDecimal(iv.right.getRational());
527        BigRational reps = eps.getRational();
528        BigDecimal e = new BigDecimal(reps);
529        BigDecimal q = new BigDecimal("0.25");
530        //System.out.println("left  = " + left);
531        //System.out.println("right = " + right);
532        e = e.multiply(d); // relative error
533        //System.out.println("e     = " + e);
534        BigDecimal dc = BigDecimal.ONE;
535        // polynomials with decimal coefficients
536        GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring);
537        GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f);
538        GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f);
539        GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp);
540        // Newton Raphson iteration: x_{n+1} = x_n - f(x_n)/f'(x_n)
541        int i = 0;
542        final int MITER = 50;
543        int dir = 0;
544        while (i++ < MITER) {
545            BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, df, d); // f(d)
546            if (fx.isZERO()) {
547                return d;
548            }
549            BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, dfp, d); // f'(d)
550            if (fpx.isZERO()) {
551                throw new NoConvergenceException("zero deriviative should not happen");
552            }
553            BigDecimal x = fx.divide(fpx);
554            BigDecimal dx = d.subtract(x);
555            //System.out.println("dx = " + dx + ", d = " + d);
556            if (d.subtract(dx).abs().compareTo(e) <= 0) {
557                return dx;
558            }
559            while (dx.compareTo(left) < 0 || dx.compareTo(right) > 0) {
560                // dx < left: dx - left < 0
561                // dx > right: dx - right > 0
562                //System.out.println("trying to leave interval");
563                if (i++ > MITER) { // dx > right: dx - right > 0
564                    throw new NoConvergenceException("no convergence after " + i + " steps");
565                }
566                if (i > MITER / 2 && dir == 0) {
567                    BigDecimal sd = new BigDecimal(iv.randomPoint().getRational());
568                    d = sd;
569                    x = sd.getZERO();
570                    logger.info("trying new random starting point " + d);
571                    i = 0;
572                    dir = 1;
573                }
574                if (i > MITER / 2 && dir == 1) {
575                    BigDecimal sd = new BigDecimal(iv.randomPoint().getRational());
576                    d = sd;
577                    x = sd.getZERO();
578                    logger.info("trying new random starting point " + d);
579                    //i = 0;
580                    dir = 2; // end
581                }
582                x = x.multiply(q); // x * 1/4
583                dx = d.subtract(x);
584                //System.out.println(" x = " + x);
585                //System.out.println("dx = " + dx);
586            }
587            d = dx;
588        }
589        throw new NoConvergenceException("no convergence after " + i + " steps");
590    }
591
592
593    /**
594     * Approximate real roots.
595     * @param f univariate polynomial, non-zero.
596     * @param eps requested interval length.
597     * @return a list of decimal approximations d such that |d-v| &lt; eps for
598     *         all real v with f(v) = 0.
599     */
600    public List<BigDecimal> approximateRoots(GenPolynomial<C> f, BigRational eps) {
601        List<Interval<C>> iv = realRoots(f);
602        List<BigDecimal> roots = new ArrayList<BigDecimal>(iv.size());
603        for (Interval<C> i : iv) {
604            BigDecimal r = null; //approximateRoot(i, f, eps); roots.add(r);
605            while (r == null) {
606                try {
607                    r = approximateRoot(i, f, eps);
608                    roots.add(r);
609                } catch (NoConvergenceException e) {
610                    // fall back to exact algorithm
611                    //System.out.println("" + e);
612                    BigRational len = i.rationalLength();
613                    len = len.divide(len.factory().fromInteger(1000));
614                    i = refineInterval(i, f, len);
615                    logger.info("fall back rootRefinement = " + i);
616                }
617            }
618        }
619        return roots;
620    }
621
622
623    /**
624     * Test if x is an approximate real root.
625     * @param x approximate real root.
626     * @param f univariate polynomial, non-zero.
627     * @param eps requested interval length.
628     * @return true if x is a decimal approximation of a real v with f(v) = 0
629     *         with |d-v| &lt; eps, else false.
630     */
631    public boolean isApproximateRoot(BigDecimal x, GenPolynomial<C> f, C eps) {
632        if (x == null) {
633            throw new IllegalArgumentException("null root not allowed");
634        }
635        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
636            return true;
637        }
638        BigDecimal e = new BigDecimal(eps.getRational());
639        e = e.multiply(new BigDecimal("1000")); // relax
640        BigDecimal dc = BigDecimal.ONE;
641        // polynomials with decimal coefficients
642        GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring);
643        GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f);
644        GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f);
645        GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp);
646        //
647        return isApproximateRoot(x, df, dfp, e);
648    }
649
650
651    /**
652     * Test if x is an approximate real root.
653     * @param x approximate real root.
654     * @param f univariate polynomial, non-zero.
655     * @param fp univariate polynomial, non-zero, deriviative of f.
656     * @param eps requested interval length.
657     * @return true if x is a decimal approximation of a real v with f(v) = 0
658     *         with |d-v| &lt; eps, else false.
659     */
660    public boolean isApproximateRoot(BigDecimal x, GenPolynomial<BigDecimal> f, GenPolynomial<BigDecimal> fp,
661                                     BigDecimal eps) {
662        if (x == null) {
663            throw new IllegalArgumentException("null root not allowed");
664        }
665        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
666            return true;
667        }
668        BigDecimal dc = BigDecimal.ONE; // only for clarity
669        // f(x)
670        BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, f, x);
671        //System.out.println("fx    = " + fx);
672        if (fx.isZERO()) {
673            return true;
674        }
675        // f'(x)
676        BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, fp, x); // f'(d)
677        //System.out.println("fpx   = " + fpx);
678        if (fpx.isZERO()) {
679            return false;
680        }
681        BigDecimal d = fx.divide(fpx);
682        if (d.isZERO()) {
683            return true;
684        }
685        if (d.abs().compareTo(eps) <= 0) {
686            return true;
687        }
688        System.out.println("x     = " + x);
689        System.out.println("d     = " + d);
690        return false;
691    }
692
693
694    /**
695     * Test if each x in R is an approximate real root.
696     * @param R ist of approximate real roots.
697     * @param f univariate polynomial, non-zero.
698     * @param eps requested interval length.
699     * @return true if each x in R is a decimal approximation of a real v with
700     *         f(v) = 0 with |d-v| &lt; eps, else false.
701     */
702    public boolean isApproximateRoot(List<BigDecimal> R, GenPolynomial<C> f, BigRational eps) {
703        if (R == null) {
704            throw new IllegalArgumentException("null root not allowed");
705        }
706        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
707            return true;
708        }
709        BigDecimal e = new BigDecimal(eps.getRational());
710        e = e.multiply(new BigDecimal("1000")); // relax
711        BigDecimal dc = BigDecimal.ONE;
712        // polynomials with decimal coefficients
713        GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring);
714        GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f);
715        GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f);
716        GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp);
717        for (BigDecimal x : R) {
718            if (!isApproximateRoot(x, df, dfp, e)) {
719                return false;
720            }
721        }
722        return true;
723    }
724
725
726    /**
727     * Fourier sequence.
728     * @param f univariate polynomial.
729     * @return (f, f', ..., f(n)) a Fourier sequence for f.
730     */
731    public List<GenPolynomial<C>> fourierSequence(GenPolynomial<C> f) {
732        List<GenPolynomial<C>> S = new ArrayList<GenPolynomial<C>>();
733        if (f == null || f.isZERO()) {
734            return S;
735        }
736        long d = f.degree();
737        GenPolynomial<C> F = f;
738        S.add(F);
739        while (d-- > 0) {
740            GenPolynomial<C> G = PolyUtil.<C> baseDeriviative(F);
741            F = G;
742            S.add(F);
743        }
744        //System.out.println("F = " + F);
745        return S;
746    }
747
748
749    /**
750     * Thom sign sequence.
751     * @param f univariate polynomial.
752     * @param v interval for a real root, f(v.left) * f(v.right) &lt; 0.
753     * @return (s1, s2, ..., sn) = (sign(f'(v)), .... sign(f(n)(v))) a
754     *         Thom sign sequence for the real root in v of f.
755     */
756    public List<Integer> signSequence(GenPolynomial<C> f, Interval<C> v) {
757        List<Integer> S = new ArrayList<Integer>();
758        GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f);
759        List<GenPolynomial<C>> fs = fourierSequence(fp);
760        for (GenPolynomial<C> p : fs) {
761            int s = realSign(v, f, p);
762            S.add(s);
763        }
764        return S;
765    }
766
767
768    /**
769     * Root number.
770     * @param f univariate polynomial.
771     * @param v interval for a real root, f(v.left) * f(v.right) &lt; 0.
772     * @return r the number of this root in the sequence a1 &lt; a2 &lt; ..., &lt; am
773     *         of all real roots of f
774     */
775    public Long realRootNumber(GenPolynomial<C> f, Interval<C> v) {
776        C M = realRootBound(f);
777        Interval<C> iv = new Interval<C>(M.negate(), v.right);
778        long r = realRootCount(iv, f);
779        if (r <= 0) {
780            logger.warn("no real root in interval " + v);
781        }
782        return r;
783    }
784
785}