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