001/*
002 * $Id$
003 */
004
005package edu.jas.root;
006
007
008import java.util.List;
009
010import org.apache.logging.log4j.Logger;
011import org.apache.logging.log4j.LogManager; 
012
013import edu.jas.arith.Rational;
014import edu.jas.poly.Complex;
015import edu.jas.structure.RingElem;
016import edu.jas.structure.RingFactory;
017
018
019/**
020 * Real root utilities. For example real root count.
021 * @author Heinz Kredel
022 */
023public class RootUtil {
024
025
026    private static final Logger logger = LogManager.getLogger(RootUtil.class);
027
028
029    private static final boolean debug = logger.isDebugEnabled();
030
031
032    /**
033     * Count changes in sign.
034     * @param <C> coefficient type.
035     * @param L list of coefficients.
036     * @return number of sign changes in L.
037     */
038    public static <C extends RingElem<C>> long signVar(List<C> L) {
039        long v = 0;
040        if (L == null || L.isEmpty()) {
041            return v;
042        }
043        C A = L.get(0);
044        for (int i = 1; i < L.size(); i++) {
045            C B = L.get(i);
046            while (B == null || B.signum() == 0) {
047                i++;
048                if (i >= L.size()) {
049                    return v;
050                }
051                B = L.get(i);
052            }
053            if (A.signum() * B.signum() < 0) {
054                v++;
055            }
056            A = B;
057        }
058        return v;
059    }
060
061
062    /**
063     * Parse interval for a real root from String.
064     * @param s String, syntax: [left, right] or [mid].
065     * @return Interval from s.
066     */
067    public static <C extends RingElem<C> & Rational> Interval<C> parseInterval(RingFactory<C> fac, String s) {
068        int r = s.length();
069        int el = s.indexOf("[");
070        if (el >= 0) {
071            int ri = s.indexOf("]");
072            if (ri > 0) {
073                r = ri;
074            }
075        } else {
076            el = -1;
077        }
078        //System.out.println("s  = " + s);
079        String iv = s.substring(el + 1, r).trim();
080        //System.out.println("iv = " + iv);
081        int k = iv.indexOf(",");
082        if (k < 0) {
083            k = s.indexOf(" ");
084        }
085        if (k < 0) {
086            C mid = fac.parse(iv);
087            return new Interval<C>(mid);
088        }
089        //System.out.println("k  = " + k + ", len = " + iv.length());
090        String ls = iv.substring(0, k).trim();
091        String rs = iv.substring(k + 1, iv.length()).trim();
092        //System.out.println("ls = " + ls + ", rs = " + rs);
093        C left = fac.parse(ls);
094        C right = fac.parse(rs);
095        logger.debug("Interval: left = {}, right = {}", left, right);
096        return new Interval<C>(left, right);
097    }
098
099
100    /**
101     * Parse rectangle for a complex root from String.
102     * @param s String, syntax: [south-west, north-east] or [mid].
103     * @return Interval from s.
104     */
105    @SuppressWarnings("unchecked")
106    public static <C extends RingElem<C> & Rational> Rectangle<C> parseRectangle(RingFactory<Complex<C>> fac,
107                    String s) {
108        int r = s.length();
109        int el = s.indexOf("[");
110        if (el >= 0) {
111            int ri = s.indexOf("]");
112            if (ri > 0) {
113                r = ri;
114            }
115        } else {
116            el = -1;
117        }
118        //System.out.println("s  = " + s);
119        String iv = s.substring(el + 1, r).trim();
120        //System.out.println("iv = " + iv);
121        int k = iv.indexOf(",");
122        if (k < 0) {
123            k = s.indexOf(" ");
124        }
125        if (k < 0) {
126            Complex<C> mid = fac.parse(iv);
127            return new Rectangle<C>(mid);
128        }
129        //System.out.println("k  = " + k + ", len = " + iv.length());
130        String ls = iv.substring(0, k).trim();
131        String rs = iv.substring(k + 1, iv.length()).trim();
132        //System.out.println("ls = " + ls + ", rs = " + rs);
133        Object osw = fac.parse(ls);
134        Object one = fac.parse(rs);
135        //System.out.println("osw = " + osw + ", one = " + one);
136        Complex<C> sw;
137        Complex<C> ne;
138        if (osw instanceof Complex) {
139            sw = (Complex<C>)osw;
140            ne = (Complex<C>)one;
141        } else if (osw instanceof ComplexAlgebraicNumber) {
142            ComplexAlgebraicNumber csw = (ComplexAlgebraicNumber) osw;
143            ComplexAlgebraicNumber cne = (ComplexAlgebraicNumber) one;
144            //System.out.println("csw::ring = " + csw.ring.algebraic.toScript());
145            sw = (Complex<C>) csw.magnitude();
146            ne = (Complex<C>) cne.magnitude();
147        } else {
148            sw = fac.getONE().negate();
149            ne = fac.getONE();
150        }
151        logger.debug("Rectangle: sw = {}, ne = {}", sw, ne);
152        return new Rectangle<C>(sw, ne);
153    }
154
155}