001/*
002 * $Id: RealRootsAbstract.java 5872 2018-07-20 16:01:46Z kredel $
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.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        // works also without this case, only for optimization 
066        // to use integral number interval end points
067        // could be obsolete: can fail if real root is in interval [r,r+1] 
068        // for too low precision or too big r, since r is approximation
069        /*
070        if (false&&(Object) M instanceof RealAlgebraicNumber) {
071            RealAlgebraicNumber Mr = (RealAlgebraicNumber) M;
072            BigRational r = Mr.magnitude();
073            //logger.info("rational root bound: " + r);
074            BigInteger i = new BigInteger(r.numerator().divide(r.denominator()));
075            i = i.sum(BigInteger.ONE);
076            //logger.info("integer root bound: " + i);
077            //M = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator()));
078            M = cfac.fromInteger(i.getVal());
079            M = M.sum(f.ring.coFac.getONE());
080            logger.info("root bound: " + M);
081            //System.out.println("M = " + M);
082            return M;
083        }
084        */
085        BigRational r = M.getRational();
086        logger.info("rational root bound: " + r);
087        BigInteger i = new BigInteger(r.numerator().divide(r.denominator()));
088        i = i.sum(BigInteger.ONE); // ceiling
089        M = cfac.fromInteger(i.getVal());
090        M = M.sum(f.ring.coFac.getONE());
091        logger.info("integer root bound: " + M);
092        //System.out.println("M = " + M);
093        return M;
094    }
095
096
097    /**
098     * Magnitude bound.
099     * @param iv interval.
100     * @param f univariate polynomial.
101     * @return B such that |f(c)| &lt; B for c in iv.
102     */
103    @SuppressWarnings("cast")
104    public C magnitudeBound(Interval<C> iv, GenPolynomial<C> f) {
105        if (f == null) {
106            return null;
107        }
108        if (f.isZERO()) {
109            return f.ring.coFac.getONE();
110        }
111        if (f.isConstant()) {
112            return f.leadingBaseCoefficient().abs();
113        }
114        GenPolynomial<C> fa = f.map(new UnaryFunctor<C, C>() {
115
116
117            public C eval(C a) {
118                return a.abs();
119            }
120        });
121        //System.out.println("fa = " + fa);
122        C M = iv.left.abs();
123        if (M.compareTo(iv.right.abs()) < 0) {
124            M = iv.right.abs();
125        }
126        //System.out.println("M = " + M);
127        RingFactory<C> cfac = f.ring.coFac;
128        C B = PolyUtil.<C> evaluateMain(cfac, fa, M);
129        // works also without this case, only for optimization 
130        // to use rational number interval end points
131        // can fail if real root is in interval [r,r+1] 
132        // for too low precision or too big r, since r is approximation
133        if ((Object) B instanceof RealAlgebraicNumber) {
134            RealAlgebraicNumber Br = (RealAlgebraicNumber) B;
135            BigRational r = Br.magnitude();
136            B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator()));
137        }
138        //System.out.println("B = " + B);
139        return B;
140    }
141
142
143    /**
144     * Bi-section point.
145     * @param iv interval with f(left) * f(right) != 0.
146     * @param f univariate polynomial, non-zero.
147     * @return a point c in the interval iv such that f(c) != 0.
148     */
149    public C bisectionPoint(Interval<C> iv, GenPolynomial<C> f) {
150        if (f == null) {
151            return null;
152        }
153        RingFactory<C> cfac = f.ring.coFac;
154        C two = cfac.fromInteger(2);
155        C c = iv.left.sum(iv.right);
156        c = c.divide(two);
157        if (f.isZERO() || f.isConstant()) {
158            return c;
159        }
160        C m = PolyUtil.<C> evaluateMain(cfac, f, c);
161        while (m.isZERO()) {
162            C d = iv.left.sum(c);
163            d = d.divide(two);
164            if (d.equals(c)) {
165                d = iv.right.sum(c);
166                d = d.divide(two);
167                if (d.equals(c)) {
168                    throw new RuntimeException("should not happen " + iv);
169                }
170            }
171            c = d;
172            m = PolyUtil.<C> evaluateMain(cfac, f, c);
173            //System.out.println("c = " + c);
174        }
175        //System.out.println("c = " + c);
176        return c;
177    }
178
179
180    /**
181     * Isolating intervals for the real roots.
182     * @param f univariate polynomial.
183     * @return a list of isolating intervalls for the real roots of f.
184     */
185    public abstract List<Interval<C>> realRoots(GenPolynomial<C> f);
186
187
188    /**
189     * Isolating intervals for the real roots.
190     * @param f univariate polynomial.
191     * @param eps requested intervals length.
192     * @return a list of isolating intervals v such that |v| &lt; eps.
193     */
194    public List<Interval<C>> realRoots(GenPolynomial<C> f, C eps) {
195        return realRoots(f, eps.getRational());
196    }
197
198
199    /**
200     * Isolating intervals for the real roots.
201     * @param f univariate polynomial.
202     * @param eps requested intervals length.
203     * @return a list of isolating intervals v such that |v| &lt; eps.
204     */
205    public List<Interval<C>> realRoots(GenPolynomial<C> f, BigRational eps) {
206        List<Interval<C>> iv = realRoots(f);
207        return refineIntervals(iv, f, eps);
208    }
209
210
211    /**
212     * Sign changes on interval bounds.
213     * @param iv root isolating interval with f(left) * f(right) != 0.
214     * @param f univariate polynomial.
215     * @return true if f(left) * f(right) &lt; 0, else false
216     */
217    public boolean signChange(Interval<C> iv, GenPolynomial<C> f) {
218        if (f == null) {
219            return false;
220        }
221        RingFactory<C> cfac = f.ring.coFac;
222        C l = PolyUtil.<C> evaluateMain(cfac, f, iv.left);
223        C r = PolyUtil.<C> evaluateMain(cfac, f, iv.right);
224        return l.signum() * r.signum() < 0;
225    }
226
227
228    /**
229     * Number of real roots in interval.
230     * @param iv interval with f(left) * f(right) != 0.
231     * @param f univariate polynomial.
232     * @return number of real roots of f in I.
233     */
234    public abstract long realRootCount(Interval<C> iv, GenPolynomial<C> f);
235
236
237    /**
238     * Half interval.
239     * @param iv root isolating interval with f(left) * f(right) &lt; 0.
240     * @param f univariate polynomial, non-zero.
241     * @return a new interval v such that |v| &lt; |iv|/2.
242     */
243    public Interval<C> halfInterval(Interval<C> iv, GenPolynomial<C> f) {
244        if (f == null || f.isZERO()) {
245            return iv;
246        }
247        BigRational len = iv.rationalLength();
248        BigRational two = len.factory().fromInteger(2);
249        BigRational eps = len.divide(two);
250        return refineInterval(iv, f, eps);
251    }
252
253
254    /**
255     * Refine interval.
256     * @param iv root isolating interval with f(left) * f(right) &lt; 0.
257     * @param f univariate polynomial, non-zero.
258     * @param eps requested interval length.
259     * @return a new interval v such that |v| &lt; eps.
260     */
261    public Interval<C> refineInterval(Interval<C> iv, GenPolynomial<C> f, BigRational eps) {
262        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
263            return iv;
264        }
265        if (iv.rationalLength().compareTo(eps) < 0) {
266            return iv;
267        }
268        RingFactory<C> cfac = f.ring.coFac;
269        C two = cfac.fromInteger(2);
270        Interval<C> v = iv;
271        while (v.rationalLength().compareTo(eps) >= 0) {
272            C c = v.left.sum(v.right);
273            c = c.divide(two);
274            //System.out.println("c = " + c);
275            //c = RootUtil.<C>bisectionPoint(v,f);
276            if (PolyUtil.<C> evaluateMain(cfac, f, c).isZERO()) {
277                v = new Interval<C>(c, c);
278                break;
279            }
280            Interval<C> iv1 = new Interval<C>(v.left, c);
281            if (signChange(iv1, f)) {
282                v = iv1;
283            } else {
284                v = new Interval<C>(c, v.right);
285            }
286        }
287        return v;
288    }
289
290
291    /**
292     * Refine intervals.
293     * @param V list of isolating intervals with f(left) * f(right) &lt; 0.
294     * @param f univariate polynomial, non-zero.
295     * @param eps requested intervals length.
296     * @return a list of new intervals v such that |v| &lt; eps.
297     */
298    public List<Interval<C>> refineIntervals(List<Interval<C>> V, GenPolynomial<C> f, BigRational eps) {
299        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
300            return V;
301        }
302        List<Interval<C>> IV = new ArrayList<Interval<C>>();
303        for (Interval<C> v : V) {
304            Interval<C> iv = refineInterval(v, f, eps);
305            IV.add(iv);
306        }
307        return IV;
308    }
309
310
311    /**
312     * Invariant interval for algebraic number sign.
313     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0.
314     * @param f univariate polynomial, non-zero.
315     * @param g univariate polynomial, gcd(f,g) == 1.
316     * @return v with v a new interval contained in iv such that g(v) != 0.
317     */
318    public abstract Interval<C> invariantSignInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g);
319
320
321    /**
322     * Real algebraic number sign.
323     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0,
324     *            with iv such that g(iv) != 0.
325     * @param f univariate polynomial, non-zero.
326     * @param g univariate polynomial, gcd(f,g) == 1.
327     * @return sign(g(iv)) .
328     */
329    public int realIntervalSign(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) {
330        if (g == null || g.isZERO()) {
331            return 0;
332        }
333        if (f == null || f.isZERO() || f.isConstant()) {
334            return g.signum();
335        }
336        if (g.isConstant()) {
337            return g.signum();
338        }
339        RingFactory<C> cfac = f.ring.coFac;
340        C c = iv.left.sum(iv.right);
341        c = c.divide(cfac.fromInteger(2));
342        C ev = PolyUtil.<C> evaluateMain(cfac, g, c);
343        //System.out.println("ev = " + ev);
344        return ev.signum();
345    }
346
347
348    /**
349     * Real algebraic number sign.
350     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0.
351     * @param f univariate polynomial, non-zero.
352     * @param g univariate polynomial, gcd(f,g) == 1.
353     * @return sign(g(v)), with v a new interval contained in iv such that g(v)
354     *         != 0.
355     */
356    public int realSign(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) {
357        if (g == null || g.isZERO()) {
358            return 0;
359        }
360        if (f == null || f.isZERO() || f.isConstant()) {
361            return g.signum();
362        }
363        if (g.isConstant()) {
364            return g.signum();
365        }
366        Interval<C> v = invariantSignInterval(iv, f, g);
367        return realIntervalSign(v, f, g);
368    }
369
370
371    /**
372     * Invariant interval for algebraic number magnitude.
373     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0.
374     * @param f univariate polynomial, non-zero.
375     * @param g univariate polynomial, gcd(f,g) == 1.
376     * @param eps length limit for interval length.
377     * @return v with v a new interval contained in iv such that |g(a) - g(b)|
378     *         &lt; eps for a, b in v in iv.
379     */
380    public Interval<C> invariantMagnitudeInterval(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g,
381                    BigRational eps) {
382        Interval<C> v = iv;
383        if (g == null || g.isZERO()) {
384            return v;
385        }
386        if (g.isConstant()) {
387            return v;
388        }
389        if (f == null || f.isZERO() || f.isConstant()) { // ?
390            return v;
391        }
392        GenPolynomial<C> gp = PolyUtil.<C> baseDeriviative(g);
393        //System.out.println("g  = " + g);
394        //System.out.println("gp = " + gp);
395        C B = magnitudeBound(iv, gp);
396        //System.out.println("B = " + B);
397
398        RingFactory<C> cfac = f.ring.coFac;
399        C two = cfac.fromInteger(2);
400
401        while (B.multiply(v.length()).getRational().compareTo(eps) >= 0) {
402            C c = v.left.sum(v.right);
403            c = c.divide(two);
404            Interval<C> im = new Interval<C>(c, v.right);
405            if (signChange(im, f)) {
406                v = im;
407            } else {
408                v = new Interval<C>(v.left, c);
409            }
410            //System.out.println("v = " + v.toDecimal());
411        }
412        return v;
413    }
414
415
416    /**
417     * Real algebraic number magnitude.
418     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0,
419     *            with iv such that |g(a) - g(b)| &lt; eps for a, b in iv.
420     * @param f univariate polynomial, non-zero.
421     * @param g univariate polynomial, gcd(f,g) == 1.
422     * @return g(iv) .
423     */
424    public C realIntervalMagnitude(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g) {
425        if (g.isZERO() || g.isConstant()) {
426            return g.leadingBaseCoefficient();
427        }
428        RingFactory<C> cfac = f.ring.coFac;
429        //if (false) {
430        //    C c = iv.left.sum(iv.right);
431        //    c = c.divide(cfac.fromInteger(2));
432        //    C ev = PolyUtil.<C> evaluateMain(cfac, g, c);
433        //    return ev;
434        //}
435        C evl = PolyUtil.<C> evaluateMain(cfac, g, iv.left);
436        C evr = PolyUtil.<C> evaluateMain(cfac, g, iv.right);
437        C ev = evl;
438        if (evl.compareTo(evr) <= 0) {
439            ev = evr;
440        }
441        //System.out.println("ev = " + ev + ", evl = " + evl + ", evr = " + evr + ", iv = " + iv);
442        return ev;
443    }
444
445
446    /**
447     * Real algebraic number magnitude.
448     * @param iv root isolating interval for f, with f(left) * f(right) &lt; 0.
449     * @param f univariate polynomial, non-zero.
450     * @param g univariate polynomial, gcd(f,g) == 1.
451     * @param eps length limit for interval length.
452     * @return g(iv) .
453     */
454    public C realMagnitude(Interval<C> iv, GenPolynomial<C> f, GenPolynomial<C> g, BigRational eps) {
455        if (g.isZERO() || g.isConstant()) {
456            return g.leadingBaseCoefficient();
457        }
458        Interval<C> v = invariantMagnitudeInterval(iv, f, g, eps);
459        return realIntervalMagnitude(v, f, g);
460    }
461
462
463    /**
464     * Approximate real root.
465     * @param iv real root isolating interval with f(left) * f(right) &lt; 0.
466     * @param f univariate polynomial, non-zero.
467     * @param eps requested interval length.
468     * @return a decimal approximation d such that |d-v| &lt; eps, for f(v) = 0,
469     *         v real.
470     */
471    public BigDecimal approximateRoot(Interval<C> iv, GenPolynomial<C> f, BigRational eps)
472                    throws NoConvergenceException {
473        if (iv == null) {
474            throw new IllegalArgumentException("null interval not allowed");
475        }
476        BigDecimal d = iv.toDecimal();
477        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
478            return d;
479        }
480        if (iv.rationalLength().compareTo(eps) < 0) {
481            return d;
482        }
483        BigDecimal left = new BigDecimal(iv.left.getRational());
484        BigDecimal right = new BigDecimal(iv.right.getRational());
485        BigRational reps = eps.getRational();
486        BigDecimal e = new BigDecimal(reps);
487        BigDecimal q = new BigDecimal("0.25");
488        //System.out.println("left  = " + left);
489        //System.out.println("right = " + right);
490        e = e.multiply(d); // relative error
491        //System.out.println("e     = " + e);
492        BigDecimal dc = BigDecimal.ONE;
493        // polynomials with decimal coefficients
494        GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring);
495        GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f);
496        GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f);
497        GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp);
498
499        // Newton Raphson iteration: x_{n+1} = x_n - f(x_n)/f'(x_n)
500        int i = 0;
501        final int MITER = 50;
502        int dir = 0;
503        while (i++ < MITER) {
504            BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, df, d); // f(d)
505            if (fx.isZERO()) {
506                return d;
507            }
508            BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, dfp, d); // f'(d)
509            if (fpx.isZERO()) {
510                throw new NoConvergenceException("zero deriviative should not happen");
511            }
512            BigDecimal x = fx.divide(fpx);
513            BigDecimal dx = d.subtract(x);
514            //System.out.println("dx = " + dx + ", d = " + d);
515            if (d.subtract(dx).abs().compareTo(e) <= 0) {
516                return dx;
517            }
518            while (dx.compareTo(left) < 0 || dx.compareTo(right) > 0) {
519                // dx < left: dx - left < 0
520                // dx > right: dx - right > 0
521                //System.out.println("trying to leave interval");
522                if (i++ > MITER) { // dx > right: dx - right > 0
523                    throw new NoConvergenceException("no convergence after " + i + " steps");
524                }
525                if (i > MITER / 2 && dir == 0) {
526                    BigDecimal sd = new BigDecimal(iv.randomPoint().getRational());
527                    d = sd;
528                    x = sd.getZERO();
529                    logger.info("trying new random starting point " + d);
530                    i = 0;
531                    dir = 1;
532                }
533                if (i > MITER / 2 && dir == 1) {
534                    BigDecimal sd = new BigDecimal(iv.randomPoint().getRational());
535                    d = sd;
536                    x = sd.getZERO();
537                    logger.info("trying new random starting point " + d);
538                    //i = 0;
539                    dir = 2; // end
540                }
541                x = x.multiply(q); // x * 1/4
542                dx = d.subtract(x);
543                //System.out.println(" x = " + x);
544                //System.out.println("dx = " + dx);
545            }
546            d = dx;
547        }
548        throw new NoConvergenceException("no convergence after " + i + " steps");
549    }
550
551
552    /**
553     * Approximate real roots.
554     * @param f univariate polynomial, non-zero.
555     * @param eps requested interval length.
556     * @return a list of decimal approximations d such that |d-v| &lt; eps for
557     *         all real v with f(v) = 0.
558     */
559    public List<BigDecimal> approximateRoots(GenPolynomial<C> f, BigRational eps) {
560        List<Interval<C>> iv = realRoots(f);
561        List<BigDecimal> roots = new ArrayList<BigDecimal>(iv.size());
562        for (Interval<C> i : iv) {
563            BigDecimal r = null; //approximateRoot(i, f, eps); roots.add(r);
564            while (r == null) {
565                try {
566                    r = approximateRoot(i, f, eps);
567                    roots.add(r);
568                } catch (NoConvergenceException e) {
569                    // fall back to exact algorithm
570                    //System.out.println("" + e);
571                    BigRational len = i.rationalLength();
572                    len = len.divide(len.factory().fromInteger(1000));
573                    i = refineInterval(i, f, len);
574                    logger.info("fall back rootRefinement = " + i);
575                }
576            }
577        }
578        return roots;
579    }
580
581
582    /**
583     * Test if x is an approximate real root.
584     * @param x approximate real root.
585     * @param f univariate polynomial, non-zero.
586     * @param eps requested interval length.
587     * @return true if x is a decimal approximation of a real v with f(v) = 0
588     *         with |d-v| &lt; eps, else false.
589     */
590    public boolean isApproximateRoot(BigDecimal x, GenPolynomial<C> f, C eps) {
591        if (x == null) {
592            throw new IllegalArgumentException("null root not allowed");
593        }
594        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
595            return true;
596        }
597        BigDecimal e = new BigDecimal(eps.getRational());
598        e = e.multiply(new BigDecimal("1000")); // relax
599        BigDecimal dc = BigDecimal.ONE;
600        // polynomials with decimal coefficients
601        GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring);
602        GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f);
603        GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f);
604        GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp);
605        //
606        return isApproximateRoot(x, df, dfp, e);
607    }
608
609
610    /**
611     * Test if x is an approximate real root.
612     * @param x approximate real root.
613     * @param f univariate polynomial, non-zero.
614     * @param fp univariate polynomial, non-zero, deriviative of f.
615     * @param eps requested interval length.
616     * @return true if x is a decimal approximation of a real v with f(v) = 0
617     *         with |d-v| &lt; eps, else false.
618     */
619    public boolean isApproximateRoot(BigDecimal x, GenPolynomial<BigDecimal> f, GenPolynomial<BigDecimal> fp,
620                    BigDecimal eps) {
621        if (x == null) {
622            throw new IllegalArgumentException("null root not allowed");
623        }
624        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
625            return true;
626        }
627        BigDecimal dc = BigDecimal.ONE; // only for clarity
628        // f(x)
629        BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, f, x);
630        //System.out.println("fx    = " + fx);
631        if (fx.isZERO()) {
632            return true;
633        }
634        // f'(x)
635        BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, fp, x); // f'(d)
636        //System.out.println("fpx   = " + fpx);
637        if (fpx.isZERO()) {
638            return false;
639        }
640        BigDecimal d = fx.divide(fpx);
641        if (d.isZERO()) {
642            return true;
643        }
644        if (d.abs().compareTo(eps) <= 0) {
645            return true;
646        }
647        System.out.println("x     = " + x);
648        System.out.println("d     = " + d);
649        return false;
650    }
651
652
653    /**
654     * Test if each x in R is an approximate real root.
655     * @param R ist of approximate real roots.
656     * @param f univariate polynomial, non-zero.
657     * @param eps requested interval length.
658     * @return true if each x in R is a decimal approximation of a real v with
659     *         f(v) = 0 with |d-v| &lt; eps, else false.
660     */
661    public boolean isApproximateRoot(List<BigDecimal> R, GenPolynomial<C> f, BigRational eps) {
662        if (R == 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 e = new BigDecimal(eps.getRational());
669        e = e.multiply(new BigDecimal("1000")); // relax
670        BigDecimal dc = BigDecimal.ONE;
671        // polynomials with decimal coefficients
672        GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring);
673        GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f);
674        GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f);
675        GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp);
676        for (BigDecimal x : R) {
677            if (!isApproximateRoot(x, df, dfp, e)) {
678                return false;
679            }
680        }
681        return true;
682    }
683
684}