001/*
002 * $Id: RootFactoryApp.java 5839 2018-05-20 20:30:09Z kredel $
003 */
004
005package edu.jas.application;
006
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.Map;
011import java.util.Set;
012
013import org.apache.log4j.Logger;
014
015import edu.jas.arith.Rational;
016import edu.jas.poly.Complex;
017import edu.jas.poly.ComplexRing;
018import edu.jas.poly.GenPolynomial;
019import edu.jas.poly.GenPolynomialRing;
020import edu.jas.poly.AlgebraicNumberRing;
021import edu.jas.poly.AlgebraicNumber;
022import edu.jas.poly.PolyUtil;
023import edu.jas.poly.TermOrder;
024import edu.jas.root.Interval;
025import edu.jas.root.RealRootTuple;
026import edu.jas.root.AlgebraicRoots;
027import edu.jas.structure.GcdRingElem;
028import edu.jas.structure.RingFactory;
029import edu.jas.ufd.SquarefreeAbstract;
030import edu.jas.ufd.SquarefreeFactory;
031
032
033/**
034 * Roots factory.
035 * @author Heinz Kredel
036 */
037public class RootFactoryApp {
038
039
040    private static final Logger logger = Logger.getLogger(RootFactoryApp.class);
041
042
043    private static final boolean debug = logger.isDebugEnabled();
044
045
046    /**
047     * Is complex algebraic number a root of a polynomial.
048     * @param f univariate polynomial.
049     * @param r complex algebraic number.
050     * @return true, if f(r) == 0, else false;
051     */
052    public static <C extends GcdRingElem<C> & Rational> boolean isRootRealCoeff(GenPolynomial<C> f,
053                    Complex<RealAlgebraicNumber<C>> r) {
054        RingFactory<C> cfac = f.ring.coFac;
055        ComplexRing<C> ccfac = new ComplexRing<C>(cfac);
056        GenPolynomialRing<Complex<C>> facc = new GenPolynomialRing<Complex<C>>(ccfac, f.ring);
057        GenPolynomial<Complex<C>> fc = PolyUtil.<C> complexFromAny(facc, f);
058        return isRoot(fc, r);
059    }
060
061
062    /**
063     * Is complex algebraic number a root of a polynomial.
064     * @param f univariate polynomial.
065     * @param r complex algebraic number.
066     * @return true, if f(r) == 0, else false;
067     */
068    public static <C extends GcdRingElem<C> & Rational> boolean isRoot(GenPolynomial<Complex<C>> f,
069                    Complex<RealAlgebraicNumber<C>> r) {
070        ComplexRing<RealAlgebraicNumber<C>> cr = r.factory();
071        GenPolynomialRing<Complex<RealAlgebraicNumber<C>>> cfac = new GenPolynomialRing<Complex<RealAlgebraicNumber<C>>>(
072                        cr, f.factory());
073        GenPolynomial<Complex<RealAlgebraicNumber<C>>> p;
074        p = PolyUtilApp.<C> convertToComplexRealCoefficients(cfac, f);
075        // test algebraic part
076        Complex<RealAlgebraicNumber<C>> a = PolyUtil.<Complex<RealAlgebraicNumber<C>>> evaluateMain(cr, p, r);
077        boolean t = a.isZERO();
078        if (!t) {
079            logger.info("f(r) = " + a + ", f = " + f + ", r  = " + r);
080            return t;
081        }
082        // test approximation? not working
083        return true;
084    }
085
086
087    /**
088     * Is complex algebraic number a root of a polynomial.
089     * @param f univariate polynomial.
090     * @param R list of complex algebraic numbers.
091     * @return true, if f(r) == 0 for all r in R, else false;
092     */
093    public static <C extends GcdRingElem<C> & Rational> boolean isRoot(GenPolynomial<Complex<C>> f,
094                    List<Complex<RealAlgebraicNumber<C>>> R) {
095        for (Complex<RealAlgebraicNumber<C>> r : R) {
096            boolean t = isRoot(f, r);
097            if (!t) {
098                return false;
099            }
100        }
101        return true;
102    }
103
104
105    /**
106     * Complex algebraic number roots.
107     * @param f univariate polynomial.
108     * @return a list of different complex algebraic numbers, with f(c) == 0 for
109     *         c in roots.
110     */
111    public static <C extends GcdRingElem<C> & Rational> List<Complex<RealAlgebraicNumber<C>>> complexAlgebraicNumbersComplex(
112                    GenPolynomial<Complex<C>> f) {
113        GenPolynomialRing<Complex<C>> pfac = f.factory();
114        if (pfac.nvar != 1) {
115            throw new IllegalArgumentException("only for univariate polynomials");
116        }
117        ComplexRing<C> cfac = (ComplexRing<C>) pfac.coFac;
118        SquarefreeAbstract<Complex<C>> engine = SquarefreeFactory.<Complex<C>> getImplementation(cfac);
119        Map<GenPolynomial<Complex<C>>, Long> F = engine.squarefreeFactors(f.monic());
120        //System.out.println("S = " + F.keySet());
121        List<Complex<RealAlgebraicNumber<C>>> list = new ArrayList<Complex<RealAlgebraicNumber<C>>>();
122        for (Map.Entry<GenPolynomial<Complex<C>>,Long> me : F.entrySet()) {
123            GenPolynomial<Complex<C>> sp = me.getKey();
124            if (sp.isConstant() || sp.isZERO()) {
125                continue;
126            }
127            List<Complex<RealAlgebraicNumber<C>>> ls = RootFactoryApp.<C> complexAlgebraicNumbersSquarefree(sp);
128            long m = me.getValue();
129            for (long i = 0L; i < m; i++) {
130                list.addAll(ls);
131            }
132        }
133        return list;
134    }
135
136
137    /**
138     * Complex algebraic number roots.
139     * @param f univariate squarefree polynomial.
140     * @return a list of different complex algebraic numbers, with f(c) == 0 for
141     *         c in roots.
142     */
143    public static <C extends GcdRingElem<C> & Rational> 
144      List<Complex<RealAlgebraicNumber<C>>> complexAlgebraicNumbersSquarefree(
145                   GenPolynomial<Complex<C>> f) {
146        GenPolynomialRing<Complex<C>> pfac = f.factory();
147        if (pfac.nvar != 1) {
148            throw new IllegalArgumentException("only for univariate polynomials");
149        }
150        ComplexRing<C> cfac = (ComplexRing<C>) pfac.coFac;
151        TermOrder to = new TermOrder(TermOrder.INVLEX);
152        GenPolynomialRing<Complex<C>> tfac = new GenPolynomialRing<Complex<C>>(cfac, 2, to); //,vars); //tord?
153        //System.out.println("tfac = " + tfac);
154        GenPolynomial<Complex<C>> t = tfac.univariate(1, 1L).sum(
155                        tfac.univariate(0, 1L).multiply(cfac.getIMAG()));
156        //System.out.println("t = " + t); // t = x + i y
157        GenPolynomialRing<C> rfac = new GenPolynomialRing<C>(cfac.ring, tfac); //tord?
158        //System.out.println("rfac = " + rfac);
159        List<Complex<RealAlgebraicNumber<C>>> list = new ArrayList<Complex<RealAlgebraicNumber<C>>>();
160        GenPolynomial<Complex<C>> sp = f;
161        if (sp.isConstant() || sp.isZERO()) {
162            return list;
163        }
164        // substitute t = x + i y
165        GenPolynomial<Complex<C>> su = PolyUtil.<Complex<C>> substituteUnivariate(sp, t);
166        //System.out.println("su = " + su);
167        su = su.monic();
168        //System.out.println("su = " + su);
169        GenPolynomial<C> re = PolyUtil.<C> realPartFromComplex(rfac, su);
170        GenPolynomial<C> im = PolyUtil.<C> imaginaryPartFromComplex(rfac, su);
171        if (debug) {
172            logger.debug("rfac = " + rfac.toScript());
173            logger.debug("t  = " + t + ", re = " + re.toScript() + ", im = " + im.toScript());
174        }
175        List<GenPolynomial<C>> li = new ArrayList<GenPolynomial<C>>(2);
176        li.add(re);
177        li.add(im);
178        Ideal<C> id = new Ideal<C>(rfac, li);
179        //System.out.println("id = " + id);
180        List<IdealWithUniv<C>> idul = id.zeroDimRootDecomposition();
181
182        IdealWithRealAlgebraicRoots<C> idr;
183        for (IdealWithUniv<C> idu : idul) {
184            //System.out.println("---idu = " + idu);
185            idr = PolyUtilApp.<C> realAlgebraicRoots(idu);
186            //System.out.println("---idr = " + idr);
187            for (List<edu.jas.root.RealAlgebraicNumber<C>> crr : idr.ran) {
188                //System.out.println("crr = " + crr);
189                RealRootTuple<C> root = new RealRootTuple<C>(crr);
190                //System.out.println("root = " + root);
191                RealAlgebraicRing<C> car = new RealAlgebraicRing<C>(idu, root);
192                //System.out.println("car = " + car);
193                List<RealAlgebraicNumber<C>> gens = car.generators();
194                //System.out.println("gens = " + gens);
195                int sg = gens.size();
196                RealAlgebraicNumber<C> rre = gens.get(sg - 2);
197                RealAlgebraicNumber<C> rim = gens.get(sg - 1);
198                ComplexRing<RealAlgebraicNumber<C>> cring = new ComplexRing<RealAlgebraicNumber<C>>(car);
199                Complex<RealAlgebraicNumber<C>> crn = new Complex<RealAlgebraicNumber<C>>(cring, rre, rim);
200                //System.out.println("crn = " + crn + " in " + crn.ring);
201                // refine intervals if necessary, not meaningful
202                list.add(crn);
203            }
204        }
205        return list;
206    }
207
208
209    /* approximation ?
210    List<ComplexAlgebraicNumber<C>> complexAlgebraicNumbersComplex(GenPolynomial<Complex<C>> f, BigRational eps)
211    */
212
213
214    /**
215     * Root reduce of real and complex algebraic numbers.
216     * @param a container of real and complex algebraic numbers.
217     * @param b container of real and complex algebraic numbers.
218     * @return container of real and complex algebraic numbers 
219     *         of the primitive element of a and b.
220     */
221    public static <C extends GcdRingElem<C> & Rational> 
222           AlgebraicRootsPrimElem<C> rootReduce(AlgebraicRoots<C> a, AlgebraicRoots<C> b) {
223        return rootReduce(a.getAlgebraicRing(), b.getAlgebraicRing());
224    }
225
226
227    /**
228     * Root reduce of real and complex algebraic numbers.
229     * @param a polynomial.
230     * @param b polynomial.
231     * @return container of real and complex algebraic numbers 
232     *         of the primitive element of a and b.
233     */
234    public static <C extends GcdRingElem<C> & Rational> 
235           AlgebraicRootsPrimElem<C> rootReduce(GenPolynomial<C> a, GenPolynomial<C> b) {
236        AlgebraicNumberRing<C> anr = new AlgebraicNumberRing<C>(a);
237        AlgebraicNumberRing<C> bnr = new AlgebraicNumberRing<C>(b);
238        return rootReduce(anr, bnr);
239    }
240
241
242    /**
243     * Root reduce of real and complex algebraic numbers.
244     * @param a algebraic number ring.
245     * @param b algebraic number ring.
246     * @return container of real and complex algebraic numbers 
247     *         of the primitive element of a and b.
248     */
249    public static <C extends GcdRingElem<C> & Rational> 
250           AlgebraicRootsPrimElem<C> rootReduce(AlgebraicNumberRing<C> a, AlgebraicNumberRing<C> b) {
251        PrimitiveElement<C> pe = PolyUtilApp.<C>primitiveElement(a, b);
252        AlgebraicRoots<C> ar = edu.jas.root.RootFactory.<C>algebraicRoots(pe.primitiveElem.modul);
253        return new AlgebraicRootsPrimElem<C>(ar, pe);
254    }
255
256
257    /**
258     * Roots of unity of real and complex algebraic numbers.
259     * @param ar container of real and complex algebraic numbers with primitive element.
260     * @return container of real and complex algebraic numbers which are roots
261     *         of unity.
262     */
263    public static <C extends GcdRingElem<C> & Rational> 
264           AlgebraicRootsPrimElem<C> rootsOfUnity(AlgebraicRootsPrimElem<C> ar) {
265        AlgebraicRoots<C> ur = edu.jas.root.RootFactory.rootsOfUnity(ar);
266        if (ar.pelem == null) {
267            return new AlgebraicRootsPrimElem<C>(ur, ar.pelem);
268        }
269        List<AlgebraicNumber<C>> al = new ArrayList<AlgebraicNumber<C>>();
270        long d = ar.pelem.primitiveElem.modul.degree();
271        AlgebraicNumber<C> c = ar.pelem.A;
272        AlgebraicNumber<C> m = c.ring.getONE();
273        for (long i = 1; i <= d; i++) {
274            m = m.multiply(c);
275            if (m.isRootOfUnity()) {
276                if (!al.contains(m)) {
277                    al.add(m);
278                }
279            }
280        }
281        c = ar.pelem.B;
282        m = c.ring.getONE();
283        for (long i = 1; i <= d; i++) {
284            m = m.multiply(c);
285            if (m.isRootOfUnity()) {
286                if (!al.contains(m)) {
287                    al.add(m);
288                }
289            }
290        }
291        return new AlgebraicRootsPrimElem<C>(ur, ar.pelem, al);
292    }
293
294}