001    /*
002     * $Id: SquarefreeInfiniteAlgebraicFieldCharP.java 3290 2010-08-26 09:18:48Z
003     * kredel $
004     */
005    
006    package edu.jas.ufd;
007    
008    
009    import java.util.ArrayList;
010    import java.util.List;
011    import java.util.SortedMap;
012    import java.util.TreeMap;
013    
014    import org.apache.log4j.Logger;
015    
016    import edu.jas.gb.Reduction;
017    import edu.jas.gb.ReductionSeq;
018    import edu.jas.gb.GroebnerBaseAbstract;
019    import edu.jas.gb.GroebnerBaseSeq;
020    import edu.jas.poly.AlgebraicNumber;
021    import edu.jas.poly.AlgebraicNumberRing;
022    import edu.jas.poly.ExpVector;
023    import edu.jas.poly.GenPolynomial;
024    import edu.jas.poly.GenPolynomialRing;
025    import edu.jas.poly.Monomial;
026    import edu.jas.poly.PolyUtil;
027    import edu.jas.structure.GcdRingElem;
028    import edu.jas.structure.Power;
029    import edu.jas.structure.RingFactory;
030    
031    
032    /**
033     * Squarefree decomposition for algebraic extensions of infinite coefficient
034     * fields of characteristic p > 0.
035     * @author Heinz Kredel
036     */
037    
038    public class SquarefreeInfiniteAlgebraicFieldCharP<C extends GcdRingElem<C>> extends
039            SquarefreeFieldCharP<AlgebraicNumber<C>> {
040    
041    
042        private static final Logger logger = Logger.getLogger(SquarefreeInfiniteAlgebraicFieldCharP.class);
043    
044    
045        private final boolean debug = logger.isDebugEnabled();
046    
047    
048        /**
049         * GCD engine for infinite ring of characteristic p base coefficients.
050         */
051        protected final SquarefreeAbstract<C> rengine;
052    
053    
054        /**
055         * Constructor.
056         */
057        public SquarefreeInfiniteAlgebraicFieldCharP(RingFactory<AlgebraicNumber<C>> fac) {
058            super(fac);
059            // isFinite() predicate now present
060            if (fac.isFinite()) {
061                throw new IllegalArgumentException("fac must be in-finite");
062            }
063            AlgebraicNumberRing<C> afac = (AlgebraicNumberRing<C>) fac;
064            GenPolynomialRing<C> rfac = afac.ring;
065            //System.out.println("rfac = " + rfac);
066            //System.out.println("rfac = " + rfac.coFac);
067            rengine = SquarefreeFactory.<C> getImplementation(rfac);
068            //System.out.println("rengine = " + rengine);
069        }
070    
071    
072        /* --------- algebraic number char-th roots --------------------- */
073    
074        /**
075         * Squarefree factors of a AlgebraicNumber.
076         * @param P AlgebraicNumber.
077         * @return [p_1 -&gt; e_1,...,p_k - &gt; e_k] with P = prod_{i=1, ..., k}
078         *         p_i**e_k.
079         */
080        @Override
081        public SortedMap<AlgebraicNumber<C>, Long> squarefreeFactors(AlgebraicNumber<C> P) {
082            if (P == null) {
083                throw new IllegalArgumentException(this.getClass().getName() + " P == null");
084            }
085            SortedMap<AlgebraicNumber<C>, Long> factors = new TreeMap<AlgebraicNumber<C>, Long>();
086            if (P.isZERO()) {
087                return factors;
088            }
089            if (P.isONE()) {
090                factors.put(P, 1L);
091                return factors;
092            }
093            GenPolynomial<C> an = P.val;
094            AlgebraicNumberRing<C> pfac = P.ring;
095            GenPolynomial<C> one = pfac.ring.getONE();
096            if (!an.isONE()) {
097                //System.out.println("an = " + an);
098                //System.out.println("rengine = " + rengine);
099                SortedMap<GenPolynomial<C>, Long> nfac = rengine.squarefreeFactors(an);
100                //System.out.println("nfac = " + nfac);
101                for (GenPolynomial<C> nfp : nfac.keySet()) {
102                    AlgebraicNumber<C> nf = new AlgebraicNumber<C>(pfac, nfp);
103                    factors.put(nf, nfac.get(nfp));
104                }
105            }
106            if (factors.size() == 0) {
107                factors.put(P, 1L);
108            }
109            return factors;
110        }
111    
112    
113        /**
114         * Characteristics root of a AlgebraicNumber.
115         * @param P AlgebraicNumber.
116         * @return [p -&gt; k] if exists k with e=charactristic(P)*k and P = p**e,
117         *         else null.
118         */
119        public SortedMap<AlgebraicNumber<C>, Long> rootCharacteristic(AlgebraicNumber<C> P) {
120            if (P == null) {
121                throw new IllegalArgumentException(this.getClass().getName() + " P == null");
122            }
123            java.math.BigInteger c = P.ring.characteristic();
124            if (c.signum() == 0) {
125                return null;
126            }
127            SortedMap<AlgebraicNumber<C>, Long> root = new TreeMap<AlgebraicNumber<C>, Long>();
128            if (P.isZERO()) {
129                return root;
130            }
131            if (P.isONE()) {
132                root.put(P, 1L);
133                return root;
134            }
135            // generate system of equations
136            AlgebraicNumberRing<C> afac = P.ring;
137            long deg = afac.modul.degree(0);
138            int d = (int) deg;
139            String[] vn = GenPolynomialRing.newVars("c", d);
140            GenPolynomialRing<AlgebraicNumber<C>> pfac = new GenPolynomialRing<AlgebraicNumber<C>>(afac, d, vn);
141            List<GenPolynomial<AlgebraicNumber<C>>> uv = (List<GenPolynomial<AlgebraicNumber<C>>>) pfac
142                    .univariateList();
143            GenPolynomial<AlgebraicNumber<C>> cp = pfac.getZERO();
144            GenPolynomialRing<C> apfac = afac.ring;
145            long i = 0;
146            for (GenPolynomial<AlgebraicNumber<C>> pa : uv) {
147                GenPolynomial<C> ca = apfac.univariate(0, i++);
148                GenPolynomial<AlgebraicNumber<C>> pb = pa.multiply(new AlgebraicNumber<C>(afac, ca));
149                cp = cp.sum(pb);
150            }
151            GenPolynomial<AlgebraicNumber<C>> cpp = Power
152                    .<GenPolynomial<AlgebraicNumber<C>>> positivePower(cp, c);
153            if (logger.isInfoEnabled()) {
154                logger.info("cp   = " + cp);
155                logger.info("cp^p = " + cpp);
156                logger.info("P    = " + P);
157            }
158            GenPolynomialRing<C> ppfac = new GenPolynomialRing<C>(apfac.coFac, pfac);
159            List<GenPolynomial<C>> gl = new ArrayList<GenPolynomial<C>>();
160            if (deg == c.longValue() && afac.modul.length() == 2) {
161                logger.info("deg(" + deg + ") == char_p(" + c.longValue() + ")");
162                for (Monomial<AlgebraicNumber<C>> m : cpp) {
163                    ExpVector f = m.e;
164                    AlgebraicNumber<C> a = m.c;
165                    //System.out.println("a  = " + a + " : " + a.toScriptFactory());
166                    GenPolynomial<C> ap = a.val;
167                    for (Monomial<C> ma : ap) {
168                        ExpVector e = ma.e;
169                        C cc = ma.c;
170                        C pc = P.val.coefficient(e);
171                        C cc1 = ((RingFactory<C>) pc.factory()).getONE();
172                        C pc1 = ((RingFactory<C>) pc.factory()).getZERO();
173                        //System.out.println("cc = " + cc + ", e = " + e);
174                        //System.out.println("pc = " + pc + " : " + cc.toScriptFactory());
175                        if (cc instanceof AlgebraicNumber && pc instanceof AlgebraicNumber) {
176                            throw new UnsupportedOperationException(
177                                    "case multiple algebraic extensions not implemented");
178                        } else if (cc instanceof Quotient && pc instanceof Quotient) {
179                            Quotient<C> ccp = (Quotient<C>) (Object) cc;
180                            Quotient<C> pcp = (Quotient<C>) (Object) pc;
181                            if (pcp.isConstant()) {
182                                //logger.error("finite field not allowed here " + afac.toScript());
183                                throw new ArithmeticException("finite field not allowed here " + afac.toScript());
184                            }
185                            //C dc = cc.divide(pc);
186                            Quotient<C> dcp = ccp.divide(pcp);
187                            if (dcp.isConstant()) { // not possible: dc.isConstant() 
188                                //System.out.println("dcp = " + dcp + " : " + cc.toScriptFactory()); //  + ", dc = " + dc);
189                                //if ( dcp.num.isConstant() ) 
190                                cc1 = cc;
191                                pc1 = pc;
192                            }
193                            GenPolynomial<C> r = new GenPolynomial<C>(ppfac, cc1, f);
194                            r = r.subtract(pc1);
195                            //System.out.println("r = " + r);
196                            gl.add(r);
197                        }
198                    }
199                }
200            } else {
201                for (Monomial<AlgebraicNumber<C>> m : cpp) {
202                    ExpVector f = m.e;
203                    AlgebraicNumber<C> a = m.c;
204                    //System.out.println("m = " + m);
205                    GenPolynomial<C> ap = a.val;
206                    for (Monomial<C> ma : ap) {
207                        ExpVector e = ma.e;
208                        C cc = ma.c;
209                        C pc = P.val.coefficient(e);
210                        GenPolynomial<C> r = new GenPolynomial<C>(ppfac, cc, f);
211                        r = r.subtract(pc);
212                        //System.out.println("r = " + r);
213                        gl.add(r);
214                    }
215                }
216            }
217            if (logger.isInfoEnabled()) {
218                logger.info("equations = " + gl);
219            }
220            // solve system of equations and construct result
221            Reduction<C> red = new ReductionSeq<C>();
222            gl = red.irreducibleSet(gl);
223            GroebnerBaseAbstract<C> bb = new GroebnerBaseSeq<C>(); //GBFactory.<C>getImplementation();
224            int z = bb.commonZeroTest(gl);
225            if (z < 0) { // no solution
226                return null;
227            }
228            if (logger.isInfoEnabled()) {
229                logger.info("solution = " + gl);
230            }
231            GenPolynomial<C> car = apfac.getZERO();
232            for (GenPolynomial<C> pl : gl) {
233                if (pl.length() <= 1) {
234                    continue;
235                }
236                if (pl.length() > 2) {
237                    throw new IllegalArgumentException("dim > 0 not implemented " + pl);
238                }
239                //System.out.println("pl = " + pl);
240                ExpVector e = pl.leadingExpVector();
241                int[] v = e.dependencyOnVariables();
242                if (v == null || v.length == 0) {
243                    continue;
244                }
245                int vi = v[0];
246                //System.out.println("vi = " + vi);
247                GenPolynomial<C> ca = apfac.univariate(0, deg - 1 - vi);
248                //System.out.println("ca = " + ca);
249                C tc = pl.trailingBaseCoefficient();
250                tc = tc.negate();
251                if (e.maxDeg() == c.longValue()) { // p-th root of tc ...
252                    //SortedMap<C, Long> br = rengine.rootCharacteristic(tc);
253                    SortedMap<C, Long> br = rengine.squarefreeFactors(tc);
254                    //System.out.println("br = " + br);
255                    if (br != null && br.size() > 0) {
256                        C cc = apfac.coFac.getONE();
257                        for (C bc : br.keySet()) {
258                            long ll = br.get(bc);
259                            if (ll % c.longValue() == 0L) {
260                                long fl = ll / c.longValue();
261                                cc = cc.multiply(Power.<C> positivePower(bc, fl));
262                            } else { // fail ?
263                                cc = cc.multiply(bc);
264                            }
265                        }
266                        //System.out.println("cc = " + cc);
267                        tc = cc;
268                    }
269                }
270                ca = ca.multiply(tc);
271                car = car.sum(ca);
272            }
273            AlgebraicNumber<C> rr = new AlgebraicNumber<C>(afac, car);
274            if (logger.isInfoEnabled()) {
275                logger.info("solution AN = " + rr);
276                //System.out.println("rr = " + rr);
277            }
278            root.put(rr, 1L);
279            return root;
280        }
281    
282    
283        /**
284         * GenPolynomial char-th root main variable.
285         * @param P univariate GenPolynomial with AlgebraicNumber coefficients.
286         * @return char-th_rootOf(P), or null, if P is no char-th root.
287         */
288        public GenPolynomial<AlgebraicNumber<C>> rootCharacteristic(GenPolynomial<AlgebraicNumber<C>> P) {
289            if (P == null || P.isZERO()) {
290                return P;
291            }
292            GenPolynomialRing<AlgebraicNumber<C>> pfac = P.ring;
293            if (pfac.nvar > 1) {
294                // go to recursion
295                GenPolynomialRing<AlgebraicNumber<C>> cfac = pfac.contract(1);
296                GenPolynomialRing<GenPolynomial<AlgebraicNumber<C>>> rfac = new GenPolynomialRing<GenPolynomial<AlgebraicNumber<C>>>(
297                        cfac, 1);
298                GenPolynomial<GenPolynomial<AlgebraicNumber<C>>> Pr = PolyUtil.<AlgebraicNumber<C>> recursive(
299                        rfac, P);
300                GenPolynomial<GenPolynomial<AlgebraicNumber<C>>> Prc = recursiveUnivariateRootCharacteristic(Pr);
301                if (Prc == null) {
302                    return null;
303                }
304                GenPolynomial<AlgebraicNumber<C>> D = PolyUtil.<AlgebraicNumber<C>> distribute(pfac, Prc);
305                return D;
306            }
307            RingFactory<AlgebraicNumber<C>> rf = pfac.coFac;
308            if (rf.characteristic().signum() != 1) {
309                // basePthRoot not possible
310                throw new IllegalArgumentException(P.getClass().getName() + " only for ModInteger polynomials "
311                        + rf);
312            }
313            long mp = rf.characteristic().longValue();
314            GenPolynomial<AlgebraicNumber<C>> d = pfac.getZERO().clone();
315            for (Monomial<AlgebraicNumber<C>> m : P) {
316                ExpVector f = m.e;
317                long fl = f.getVal(0);
318                if (fl % mp != 0) {
319                    return null;
320                }
321                fl = fl / mp;
322                SortedMap<AlgebraicNumber<C>, Long> sm = rootCharacteristic(m.c);
323                if (sm == null) {
324                    return null;
325                }
326                if (logger.isInfoEnabled()) {
327                    logger.info("sm_alg,root = " + sm);
328                }
329                AlgebraicNumber<C> r = rf.getONE();
330                for (AlgebraicNumber<C> rp : sm.keySet()) {
331                    long gl = sm.get(rp);
332                    if (gl > 1) {
333                        rp = Power.<AlgebraicNumber<C>> positivePower(rp, gl);
334                    }
335                    r = r.multiply(rp);
336                }
337                ExpVector e = ExpVector.create(1, 0, fl);
338                d.doPutToMap(e, r);
339            }
340            logger.info("sm_alg,root,d = " + d);
341            return d;
342        }
343    
344    
345        /**
346         * GenPolynomial char-th root univariate polynomial.
347         * @param P GenPolynomial.
348         * @return char-th_rootOf(P).
349         */
350        @Override
351        public GenPolynomial<AlgebraicNumber<C>> baseRootCharacteristic(GenPolynomial<AlgebraicNumber<C>> P) {
352            if (P == null || P.isZERO()) {
353                return P;
354            }
355            GenPolynomialRing<AlgebraicNumber<C>> pfac = P.ring;
356            if (pfac.nvar > 1) {
357                // basePthRoot not possible by return type
358                throw new IllegalArgumentException(P.getClass().getName() + " only for univariate polynomials");
359            }
360            RingFactory<AlgebraicNumber<C>> rf = pfac.coFac;
361            if (rf.characteristic().signum() != 1) {
362                // basePthRoot not possible
363                throw new IllegalArgumentException(P.getClass().getName() + " only for char p > 0 " + rf);
364            }
365            long mp = rf.characteristic().longValue();
366            GenPolynomial<AlgebraicNumber<C>> d = pfac.getZERO().clone();
367            for (Monomial<AlgebraicNumber<C>> m : P) {
368                //System.out.println("m = " + m);
369                ExpVector f = m.e;
370                long fl = f.getVal(0);
371                if (fl % mp != 0) {
372                    return null;
373                }
374                fl = fl / mp;
375                SortedMap<AlgebraicNumber<C>, Long> sm = rootCharacteristic(m.c);
376                if (sm == null) {
377                    return null;
378                }
379                if (logger.isInfoEnabled()) {
380                    logger.info("sm_alg,base,root = " + sm);
381                }
382                AlgebraicNumber<C> r = rf.getONE();
383                for (AlgebraicNumber<C> rp : sm.keySet()) {
384                    //System.out.println("rp = " + rp);
385                    long gl = sm.get(rp);
386                    //System.out.println("gl = " + gl);
387                    AlgebraicNumber<C> re = rp;
388                    if (gl > 1) {
389                        re = Power.<AlgebraicNumber<C>> positivePower(rp, gl);
390                    }
391                    //System.out.println("re = " + re);
392                    r = r.multiply(re);
393                }
394                ExpVector e = ExpVector.create(1, 0, fl);
395                d.doPutToMap(e, r);
396            }
397            if (logger.isInfoEnabled()) {
398                logger.info("sm_alg,base,d = " + d);
399            }
400            return d;
401        }
402    
403    
404        /**
405         * GenPolynomial char-th root univariate polynomial with polynomial
406         * coefficients.
407         * @param P recursive univariate GenPolynomial.
408         * @return char-th_rootOf(P), or null if P is no char-th root.
409         */
410        @Override
411        public GenPolynomial<GenPolynomial<AlgebraicNumber<C>>> recursiveUnivariateRootCharacteristic(
412                GenPolynomial<GenPolynomial<AlgebraicNumber<C>>> P) {
413            if (P == null || P.isZERO()) {
414                return P;
415            }
416            GenPolynomialRing<GenPolynomial<AlgebraicNumber<C>>> pfac = P.ring;
417            if (pfac.nvar > 1) {
418                // basePthRoot not possible by return type
419                throw new IllegalArgumentException(P.getClass().getName()
420                        + " only for univariate recursive polynomials");
421            }
422            RingFactory<GenPolynomial<AlgebraicNumber<C>>> rf = pfac.coFac;
423            if (rf.characteristic().signum() != 1) {
424                // basePthRoot not possible
425                throw new IllegalArgumentException(P.getClass().getName() + " only for char p > 0 " + rf);
426            }
427            long mp = rf.characteristic().longValue();
428            GenPolynomial<GenPolynomial<AlgebraicNumber<C>>> d = pfac.getZERO().clone();
429            for (Monomial<GenPolynomial<AlgebraicNumber<C>>> m : P) {
430                ExpVector f = m.e;
431                long fl = f.getVal(0);
432                if (fl % mp != 0) {
433                    return null;
434                }
435                fl = fl / mp;
436                GenPolynomial<AlgebraicNumber<C>> r = rootCharacteristic(m.c);
437                if (r == null) {
438                    return null;
439                }
440                ExpVector e = ExpVector.create(1, 0, fl);
441                d.doPutToMap(e, r);
442            }
443            return d;
444        }
445    
446    }