001/*
002 * $Id: RealRootsAbstract.java 4961 2014-10-17 18:59:39Z kredel $
003 */
004
005package edu.jas.root;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import org.apache.log4j.Logger;
012
013import edu.jas.arith.BigDecimal;
014import edu.jas.arith.BigInteger;
015import edu.jas.arith.BigRational;
016import edu.jas.arith.Rational;
017import edu.jas.poly.GenPolynomial;
018import edu.jas.poly.GenPolynomialRing;
019import edu.jas.poly.PolyUtil;
020import edu.jas.structure.RingElem;
021import edu.jas.structure.RingFactory;
022import edu.jas.structure.UnaryFunctor;
023
024
025/**
026 * Real roots abstract class.
027 * @param <C> coefficient type.
028 * @author Heinz Kredel
029 */
030public abstract class RealRootsAbstract<C extends RingElem<C> & Rational> implements RealRoots<C> {
031
032
033    private static final Logger logger = Logger.getLogger(RealRootsAbstract.class);
034
035
036    //private static boolean debug = logger.isDebugEnabled();
037
038
039    /**
040     * Real root bound. With f(M) * f(-M) != 0.
041     * @param f univariate polynomial.
042     * @return M such that -M &lt; root(f) &lt; M.
043     */
044    public C realRootBound(GenPolynomial<C> f) {
045        if (f == null) {
046            return null;
047        }
048        RingFactory<C> cfac = f.ring.coFac;
049        C M = cfac.getONE();
050        if (f.isZERO()) {
051            return M;
052        }
053        if (f.isConstant()) {
054            M = f.leadingBaseCoefficient().abs().sum(cfac.getONE());
055            return M;
056        }
057        C a = f.leadingBaseCoefficient().abs();
058        for (C c : f.getMap().values()) {
059            C d = c.abs().divide(a);
060            if (M.compareTo(d) < 0) {
061                M = d;
062            }
063        }
064        // works also without this case, only for optimization 
065        // to use integral number interval end points
066        // could be obsolete: can fail if real root is in interval [r,r+1] 
067        // for too low precision or too big r, since r is approximation
068        /*
069        if (false&&(Object) M instanceof RealAlgebraicNumber) {
070            RealAlgebraicNumber Mr = (RealAlgebraicNumber) M;
071            BigRational r = Mr.magnitude();
072            //logger.info("rational root bound: " + r);
073            BigInteger i = new BigInteger(r.numerator().divide(r.denominator()));
074            i = i.sum(BigInteger.ONE);
075            //logger.info("integer root bound: " + i);
076            //M = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator()));
077            M = cfac.fromInteger(i.getVal());
078            M = M.sum(f.ring.coFac.getONE());
079            logger.info("root bound: " + M);
080            //System.out.println("M = " + M);
081            return M;
082        }
083        */
084        BigRational r = M.getRational();
085        logger.info("rational root bound: " + r);
086        BigInteger i = new BigInteger(r.numerator().divide(r.denominator()));
087        i = i.sum(BigInteger.ONE); // ceiling
088        M = cfac.fromInteger(i.getVal());
089        M = M.sum(f.ring.coFac.getONE());
090        logger.info("integer root bound: " + M);
091        //System.out.println("M = " + M);
092        return M;
093    }
094
095
096    /**
097     * Magnitude bound.
098     * @param iv interval.
099     * @param f univariate polynomial.
100     * @return B such that |f(c)| &lt; B for c in iv.
101     */
102    @SuppressWarnings("cast")
103    public C magnitudeBound(Interval<C> iv, GenPolynomial<C> f) {
104        if (f == null) {
105            return null;
106        }
107        if (f.isZERO()) {
108            return f.ring.coFac.getONE();
109        }
110        if (f.isConstant()) {
111            return f.leadingBaseCoefficient().abs();
112        }
113        GenPolynomial<C> fa = f.map(new UnaryFunctor<C, C>() {
114
115
116            public C eval(C a) {
117                return a.abs();
118            }
119        });
120        //System.out.println("fa = " + fa);
121        C M = iv.left.abs();
122        if (M.compareTo(iv.right.abs()) < 0) {
123            M = iv.right.abs();
124        }
125        //System.out.println("M = " + M);
126        RingFactory<C> cfac = f.ring.coFac;
127        C B = PolyUtil.<C> evaluateMain(cfac, fa, M);
128        // works also without this case, only for optimization 
129        // to use rational number interval end points
130        // can fail if real root is in interval [r,r+1] 
131        // for too low precision or too big r, since r is approximation
132        if ((Object) B instanceof RealAlgebraicNumber) {
133            RealAlgebraicNumber Br = (RealAlgebraicNumber) B;
134            BigRational r = Br.magnitude();
135            B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator()));
136        }
137        //System.out.println("B = " + B);
138        return B;
139    }
140
141
142    /**
143     * Bi-section point.
144     * @param iv interval with f(left) * f(right) != 0.
145     * @param f univariate polynomial, non-zero.
146     * @return a point c in the interval iv such that f(c) != 0.
147     */
148    public C bisectionPoint(Interval<C> iv, GenPolynomial<C> f) {
149        if (f == null) {
150            return null;
151        }
152        RingFactory<C> cfac = f.ring.coFac;
153        C two = cfac.fromInteger(2);
154        C c = iv.left.sum(iv.right);
155        c = c.divide(two);
156        if (f.isZERO() || f.isConstant()) {
157            return c;
158        }
159        C m = PolyUtil.<C> evaluateMain(cfac, f, c);
160        while (m.isZERO()) {
161            C d = iv.left.sum(c);
162            d = d.divide(two);
163            if (d.equals(c)) {
164                d = iv.right.sum(c);
165                d = d.divide(two);
166                if (d.equals(c)) {
167                    throw new RuntimeException("should not happen " + iv);
168                }
169            }
170            c = d;
171            m = PolyUtil.<C> evaluateMain(cfac, f, c);
172            //System.out.println("c = " + c);
173        }
174        //System.out.println("c = " + c);
175        return c;
176    }
177
178
179    /**
180     * Isolating intervals for the real roots.
181     * @param f univariate polynomial.
182     * @return a list of isolating intervalls for the real roots of f.
183     */
184    public abstract List<Interval<C>> realRoots(GenPolynomial<C> f);
185
186
187    /**
188     * Isolating intervals for the real roots.
189     * @param f univariate polynomial.
190     * @param eps requested intervals length.
191     * @return a list of isolating intervals v such that |v| &lt; eps.
192     */
193    public List<Interval<C>> realRoots(GenPolynomial<C> f, C eps) {
194        List<Interval<C>> iv = realRoots(f);
195        return refineIntervals(iv, f, eps);
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        C e = f.ring.coFac.parse(eps.toString());
207        return realRoots(f, e);
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        C len = iv.length();
248        C two = len.factory().fromInteger(2);
249        C 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, C eps) {
262        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
263            return iv;
264        }
265        if (iv.length().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.length().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, C 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                    C 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()).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, C 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, C 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.length().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) { // dx < left: dx - left < 0
519                                                                        // dx > right: dx - right > 0
520                //System.out.println("trying to leave interval");
521                if (i++ > MITER) { // dx > right: dx - right > 0
522                    throw new NoConvergenceException("no convergence after " + i + " steps");
523                }
524                if (i > MITER / 2 && dir == 0) {
525                    BigDecimal sd = new BigDecimal(iv.randomPoint().getRational());
526                    d = sd;
527                    x = sd.getZERO();
528                    logger.info("trying new random starting point " + d);
529                    i = 0;
530                    dir = 1;
531                }
532                if (i > MITER / 2 && dir == 1) {
533                    BigDecimal sd = new BigDecimal(iv.randomPoint().getRational());
534                    d = sd;
535                    x = sd.getZERO();
536                    logger.info("trying new random starting point " + d);
537                    //i = 0;
538                    dir = 2; // end
539                }
540                x = x.multiply(q); // x * 1/4
541                dx = d.subtract(x);
542                //System.out.println(" x = " + x);
543                //System.out.println("dx = " + dx);
544            }
545            d = dx;
546        }
547        throw new NoConvergenceException("no convergence after " + i + " steps");
548    }
549
550
551    /**
552     * Approximate real roots.
553     * @param f univariate polynomial, non-zero.
554     * @param eps requested interval length.
555     * @return a list of decimal approximations d such that |d-v| &lt; eps for
556     *         all real v with f(v) = 0.
557     */
558    public List<BigDecimal> approximateRoots(GenPolynomial<C> f, C eps) {
559        List<Interval<C>> iv = realRoots(f);
560        List<BigDecimal> roots = new ArrayList<BigDecimal>(iv.size());
561        for (Interval<C> i : iv) {
562            BigDecimal r = null; //approximateRoot(i, f, eps); roots.add(r);
563            while (r == null) {
564                try {
565                    r = approximateRoot(i, f, eps);
566                    roots.add(r);
567                } catch (NoConvergenceException e) {
568                    // fall back to exact algorithm
569                    //System.out.println("" + e);
570                    C len = i.length();
571                    len = len.divide(f.ring.coFac.fromInteger(1000));
572                    i = refineInterval(i, f, len);
573                    logger.info("fall back rootRefinement = " + i);
574                }
575            }
576        }
577        return roots;
578    }
579
580
581    /**
582     * Test if x is an approximate real root.
583     * @param x approximate real root.
584     * @param f univariate polynomial, non-zero.
585     * @param eps requested interval length.
586     * @return true if x is a decimal approximation of a real v with f(v) = 0
587     *         with |d-v| &lt; eps, else false.
588     */
589    public boolean isApproximateRoot(BigDecimal x, GenPolynomial<C> f, C eps) {
590        if (x == null) {
591            throw new IllegalArgumentException("null root not allowed");
592        }
593        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
594            return true;
595        }
596        BigDecimal e = new BigDecimal(eps.getRational());
597        e = e.multiply(new BigDecimal("1000")); // relax
598        BigDecimal dc = BigDecimal.ONE;
599        // polynomials with decimal coefficients
600        GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring);
601        GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f);
602        GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f);
603        GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp);
604        //
605        return isApproximateRoot(x, df, dfp, e);
606    }
607
608
609    /**
610     * Test if x is an approximate real root.
611     * @param x approximate real root.
612     * @param f univariate polynomial, non-zero.
613     * @param fp univariate polynomial, non-zero, deriviative of f.
614     * @param eps requested interval length.
615     * @return true if x is a decimal approximation of a real v with f(v) = 0
616     *         with |d-v| &lt; eps, else false.
617     */
618    public boolean isApproximateRoot(BigDecimal x, GenPolynomial<BigDecimal> f, GenPolynomial<BigDecimal> fp,
619                    BigDecimal eps) {
620        if (x == null) {
621            throw new IllegalArgumentException("null root not allowed");
622        }
623        if (f == null || f.isZERO() || f.isConstant() || eps == null) {
624            return true;
625        }
626        BigDecimal dc = BigDecimal.ONE; // only for clarity
627        // f(x)
628        BigDecimal fx = PolyUtil.<BigDecimal> evaluateMain(dc, f, x);
629        //System.out.println("fx    = " + fx);
630        if (fx.isZERO()) {
631            return true;
632        }
633        // f'(x)
634        BigDecimal fpx = PolyUtil.<BigDecimal> evaluateMain(dc, fp, x); // f'(d)
635        //System.out.println("fpx   = " + fpx);
636        if (fpx.isZERO()) {
637            return false;
638        }
639        BigDecimal d = fx.divide(fpx);
640        if (d.isZERO()) {
641            return true;
642        }
643        if (d.abs().compareTo(eps) <= 0) {
644            return true;
645        }
646        System.out.println("x     = " + x);
647        System.out.println("d     = " + d);
648        return false;
649    }
650
651
652    /**
653     * Test if each x in R is an approximate real root.
654     * @param R ist of approximate real roots.
655     * @param f univariate polynomial, non-zero.
656     * @param eps requested interval length.
657     * @return true if each x in R is a decimal approximation of a real v with
658     *         f(v) = 0 with |d-v| &lt; eps, else false.
659     */
660    public boolean isApproximateRoot(List<BigDecimal> R, GenPolynomial<C> f, C eps) {
661        if (R == 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 e = new BigDecimal(eps.getRational());
668        e = e.multiply(new BigDecimal("1000")); // relax
669        BigDecimal dc = BigDecimal.ONE;
670        // polynomials with decimal coefficients
671        GenPolynomialRing<BigDecimal> dfac = new GenPolynomialRing<BigDecimal>(dc, f.ring);
672        GenPolynomial<BigDecimal> df = PolyUtil.<C> decimalFromRational(dfac, f);
673        GenPolynomial<C> fp = PolyUtil.<C> baseDeriviative(f);
674        GenPolynomial<BigDecimal> dfp = PolyUtil.<C> decimalFromRational(dfac, fp);
675        for (BigDecimal x : R) {
676            if (!isApproximateRoot(x, df, dfp, e)) {
677                return false;
678            }
679        }
680        return true;
681    }
682
683}