001/*
002 * $Id$
003 */
004
005package edu.jas.application;
006
007
008import java.util.Map;
009import java.util.Set;
010import java.util.SortedMap;
011
012import org.apache.logging.log4j.Logger;
013import org.apache.logging.log4j.LogManager; 
014
015import edu.jas.poly.ExpVector;
016import edu.jas.poly.GenSolvablePolynomial;
017import edu.jas.poly.RecSolvablePolynomial;
018import edu.jas.poly.TableRelation;
019import edu.jas.structure.GcdRingElem;
020
021
022/**
023 * ResidueSolvablePolynomial generic solvable polynomials with solvable residue
024 * coefficients implementing RingElem. n-variate ordered solvable polynomials
025 * over solvable residue coefficients. Objects of this class are intended to be
026 * immutable. The implementation is based on TreeMap respectively SortedMap from
027 * exponents to coefficients by extension of GenPolynomial.
028 * @param <C> coefficient type
029 * @author Heinz Kredel
030 */
031
032public class ResidueSolvablePolynomial<C extends GcdRingElem<C>> extends
033                GenSolvablePolynomial<SolvableResidue<C>> {
034
035
036    /**
037     * The factory for the recursive solvable polynomial ring. Hides super.ring.
038     */
039    public final ResidueSolvablePolynomialRing<C> ring;
040
041
042    private static final Logger logger = LogManager.getLogger(ResidueSolvablePolynomial.class);
043
044
045    private static final boolean debug = logger.isDebugEnabled();
046
047
048    /**
049     * Constructor for zero ResidueSolvablePolynomial.
050     * @param r solvable polynomial ring factory.
051     */
052    public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing<C> r) {
053        super(r);
054        ring = r;
055    }
056
057
058    /**
059     * Constructor for ResidueSolvablePolynomial.
060     * @param r solvable polynomial ring factory.
061     * @param e exponent.
062     */
063    public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing<C> r, ExpVector e) {
064        this(r);
065        val.put(e, ring.getONECoefficient());
066    }
067
068
069    /**
070     * Constructor for ResidueSolvablePolynomial.
071     * @param r solvable polynomial ring factory.
072     * @param c coefficient polynomial.
073     * @param e exponent.
074     */
075    public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing<C> r, SolvableResidue<C> c, ExpVector e) {
076        this(r);
077        if (c != null && !c.isZERO()) {
078            val.put(e, c);
079        }
080    }
081
082
083    /**
084     * Constructor for ResidueSolvablePolynomial.
085     * @param r solvable polynomial ring factory.
086     * @param c coefficient polynomial.
087     */
088    public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing<C> r, SolvableResidue<C> c) {
089        this(r, c, r.evzero);
090    }
091
092
093    /**
094     * Constructor for ResidueSolvablePolynomial.
095     * @param r solvable polynomial ring factory.
096     * @param S solvable polynomial.
097     */
098    public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing<C> r,
099                    GenSolvablePolynomial<SolvableResidue<C>> S) {
100        this(r, S.getMap());
101    }
102
103
104    /**
105     * Constructor for ResidueSolvablePolynomial.
106     * @param r solvable polynomial ring factory.
107     * @param v the SortedMap of some other (solvable) polynomial.
108     */
109    protected ResidueSolvablePolynomial(ResidueSolvablePolynomialRing<C> r,
110                    SortedMap<ExpVector, SolvableResidue<C>> v) {
111        this(r);
112        val.putAll(v); // assume no zero coefficients
113    }
114
115
116    /**
117     * Get the corresponding element factory.
118     * @return factory for this Element.
119     * @see edu.jas.structure.Element#factory()
120     */
121    @Override
122    public ResidueSolvablePolynomialRing<C> factory() {
123        return ring;
124    }
125
126
127    /**
128     * Clone this ResidueSolvablePolynomial.
129     * @see java.lang.Object#clone()
130     */
131    @Override
132    public ResidueSolvablePolynomial<C> copy() {
133        return new ResidueSolvablePolynomial<C>(ring, this.val);
134    }
135
136
137    /**
138     * Comparison with any other object.
139     * @see java.lang.Object#equals(java.lang.Object)
140     */
141    @Override
142    public boolean equals(Object B) {
143        if (!(B instanceof ResidueSolvablePolynomial)) {
144            return false;
145        }
146        return super.equals(B);
147    }
148
149
150    /**
151     * Hash code for this polynomial.
152     * @see java.lang.Object#hashCode()
153     */
154    @Override
155    public int hashCode() {
156        return super.hashCode();
157    }
158
159
160    /**
161     * ResidueSolvablePolynomial multiplication.
162     * @param Bp ResidueSolvablePolynomial.
163     * @return this*Bp, where * denotes solvable multiplication.
164     */
165    public ResidueSolvablePolynomial<C> multiply(ResidueSolvablePolynomial<C> Bp) {
166        if (Bp == null || Bp.isZERO()) {
167            return ring.getZERO();
168        }
169        if (this.isZERO()) {
170            return this;
171        }
172        assert (ring.nvar == Bp.ring.nvar);
173        if (debug) {
174            logger.debug("ring = " + ring);
175        }
176        ExpVector Z = ring.evzero;
177        ResidueSolvablePolynomial<C> Dp = ring.getZERO().copy();
178        ResidueSolvablePolynomial<C> zero = ring.getZERO().copy();
179        SolvableResidue<C> one = ring.getONECoefficient();
180
181        //ResidueSolvablePolynomial<C> C1 = null;
182        //ResidueSolvablePolynomial<C> C2 = null;
183        Map<ExpVector, SolvableResidue<C>> A = val;
184        Map<ExpVector, SolvableResidue<C>> B = Bp.val;
185        Set<Map.Entry<ExpVector, SolvableResidue<C>>> Bk = B.entrySet();
186        for (Map.Entry<ExpVector, SolvableResidue<C>> y : A.entrySet()) {
187            SolvableResidue<C> a = y.getValue();
188            ExpVector e = y.getKey();
189            if (debug)
190                logger.info("e = " + e + ", a = " + a);
191            //int[] ep = e.dependencyOnVariables();
192            //int el1 = ring.nvar + 1;
193            //if (ep.length > 0) {
194            //    el1 = ep[0];
195            //}
196            //int el1s = ring.nvar + 1 - el1;
197            for (Map.Entry<ExpVector, SolvableResidue<C>> x : Bk) {
198                SolvableResidue<C> b = x.getValue();
199                ExpVector f = x.getKey();
200                if (debug)
201                    logger.info("f = " + f + ", b = " + b);
202                int[] fp = f.dependencyOnVariables();
203                int fl1 = 0;
204                if (fp.length > 0) {
205                    fl1 = fp[fp.length - 1];
206                }
207                int fl1s = ring.nvar + 1 - fl1;
208                // polynomial coefficient multiplication 
209                ResidueSolvablePolynomial<C> Cps = ring.getZERO().copy();
210                //ResidueSolvablePolynomial<C> Cs = null;
211                if (ring.polCoeff.coeffTable.isEmpty() || b.isConstant() || e.isZERO()) { // symmetric
212                    Cps = new ResidueSolvablePolynomial<C>(ring, b, e);
213                    if (debug)
214                        logger.info("symmetric coeff: b = " + b + ", e = " + e);
215                } else { // unsymmetric
216                    if (debug)
217                        logger.info("unsymmetric coeff: b = " + b + ", e = " + e);
218                    // recursive polynomial coefficient multiplication : e * b.val
219                    RecSolvablePolynomial<C> rsp1 = new RecSolvablePolynomial<C>(ring.polCoeff, e);
220                    RecSolvablePolynomial<C> rsp2 = new RecSolvablePolynomial<C>(ring.polCoeff, b.val);
221                    RecSolvablePolynomial<C> rsp3 = rsp1.multiply(rsp2);
222                    Cps = ring.fromPolyCoefficients(rsp3);
223                }
224                if (debug) {
225                    logger.info("coeff-poly: Cps = " + Cps);
226                }
227                // polynomial multiplication 
228                ResidueSolvablePolynomial<C> Dps = ring.getZERO().copy();
229                ResidueSolvablePolynomial<C> Ds = null;
230                ResidueSolvablePolynomial<C> D1, D2;
231                if (ring.table.isEmpty() || Cps.isConstant() || f.isZERO()) { // symmetric
232                    if (debug)
233                        logger.info("symmetric poly: b = " + b + ", e = " + e);
234                    ExpVector g = e.sum(f);
235                    if (Cps.isConstant()) {
236                        Ds = new ResidueSolvablePolynomial<C>(ring, Cps.leadingBaseCoefficient(), g); // symmetric!
237                    } else {
238                        Ds = Cps.shift(f); // symmetric
239                    }
240                } else { // eventually unsymmetric
241                    if (debug)
242                        logger.info("unsymmetric poly: Cps = " + Cps + ", f = " + f);
243                    for (Map.Entry<ExpVector, SolvableResidue<C>> z : Cps.val.entrySet()) {
244                        // split g = g1 * g2, f = f1 * f2
245                        SolvableResidue<C> c = z.getValue();
246                        ExpVector g = z.getKey();
247                        if (debug)
248                            logger.info("g = " + g + ", c = " + c);
249                        int[] gp = g.dependencyOnVariables();
250                        int gl1 = ring.nvar + 1;
251                        if (gp.length > 0) {
252                            gl1 = gp[0];
253                        }
254                        int gl1s = ring.nvar + 1 - gl1;
255                        if (gl1s <= fl1s) { // symmetric
256                            ExpVector h = g.sum(f);
257                            if (debug)
258                                logger.info("disjoint poly: g = " + g + ", f = " + f + ", h = " + h);
259                            Ds = (ResidueSolvablePolynomial<C>) zero.sum(one, h); // symmetric!
260                        } else {
261                            ExpVector g1 = g.subst(gl1, 0);
262                            ExpVector g2 = Z.subst(gl1, g.getVal(gl1)); // bug el1, gl1
263                            ExpVector g4;
264                            ExpVector f1 = f.subst(fl1, 0);
265                            ExpVector f2 = Z.subst(fl1, f.getVal(fl1));
266                            if (debug)
267                                logger.info("poly, g1 = " + g1 + ", f1 = " + f1 + ", Dps = " + Dps);
268                            if (debug)
269                                logger.info("poly, g2 = " + g2 + ", f2 = " + f2);
270                            TableRelation<SolvableResidue<C>> rel = ring.table.lookup(g2, f2);
271                            if (debug)
272                                logger.info("poly, g  = " + g + ", f  = " + f + ", rel = " + rel);
273                            Ds = new ResidueSolvablePolynomial<C>(ring, rel.p); //ring.copy(rel.p);
274                            if (rel.f != null) {
275                                D2 = new ResidueSolvablePolynomial<C>(ring, one, rel.f);
276                                Ds = Ds.multiply(D2);
277                                if (rel.e == null) {
278                                    g4 = g2;
279                                } else {
280                                    g4 = g2.subtract(rel.e);
281                                }
282                                ring.table.update(g4, f2, Ds);
283                            }
284                            if (rel.e != null) {
285                                D1 = new ResidueSolvablePolynomial<C>(ring, one, rel.e);
286                                Ds = D1.multiply(Ds);
287                                ring.table.update(g2, f2, Ds);
288                            }
289                            if (!f1.isZERO()) {
290                                D2 = new ResidueSolvablePolynomial<C>(ring, one, f1);
291                                Ds = Ds.multiply(D2);
292                                //ring.table.update(?,f1,Ds)
293                            }
294                            if (!g1.isZERO()) {
295                                D1 = new ResidueSolvablePolynomial<C>(ring, one, g1);
296                                Ds = D1.multiply(Ds);
297                                //ring.table.update(e1,?,Ds)
298                            }
299                        }
300                        Ds = Ds.multiplyLeft(c); // assume c commutes with Cs
301                        Dps = (ResidueSolvablePolynomial<C>) Dps.sum(Ds);
302                    } // end Dps loop
303                    Ds = Dps;
304                }
305                Ds = Ds.multiplyLeft(a); // multiply(a,b); // non-symmetric 
306                if (debug)
307                    logger.debug("Ds = " + Ds);
308                Dp = (ResidueSolvablePolynomial<C>) Dp.sum(Ds);
309            } // end B loop
310        } // end A loop
311        return Dp;
312    }
313
314
315    /**
316     * ResidueSolvablePolynomial left and right multiplication. Product with two
317     * polynomials.
318     * @param S ResidueSolvablePolynomial.
319     * @param T ResidueSolvablePolynomial.
320     * @return S*this*T.
321     */
322    public ResidueSolvablePolynomial<C> multiply(ResidueSolvablePolynomial<C> S,
323                    ResidueSolvablePolynomial<C> T) {
324        if (S.isZERO() || T.isZERO() || this.isZERO()) {
325            return ring.getZERO();
326        }
327        if (S.isONE()) {
328            return multiply(T);
329        }
330        if (T.isONE()) {
331            return S.multiply(this);
332        }
333        return S.multiply(this).multiply(T);
334    }
335
336
337    /**
338     * ResidueSolvablePolynomial multiplication. Product with coefficient ring
339     * element.
340     * @param b coefficient polynomial.
341     * @return this*b, where * is coefficient multiplication.
342     */
343    @Override
344    public ResidueSolvablePolynomial<C> multiply(SolvableResidue<C> b) {
345        ResidueSolvablePolynomial<C> Cp = ring.getZERO().copy();
346        if (b == null || b.isZERO()) {
347            return Cp;
348        }
349        Cp = new ResidueSolvablePolynomial<C>(ring, b, ring.evzero);
350        return multiply(Cp);
351    }
352
353
354    /**
355     * ResidueSolvablePolynomial left and right multiplication. Product with
356     * coefficient ring element.
357     * @param b coefficient polynomial.
358     * @param c coefficient polynomial.
359     * @return b*this*c, where * is coefficient multiplication.
360     */
361    @Override
362    public ResidueSolvablePolynomial<C> multiply(SolvableResidue<C> b, SolvableResidue<C> c) {
363        ResidueSolvablePolynomial<C> Cp = ring.getZERO().copy();
364        if (b == null || b.isZERO()) {
365            return Cp;
366        }
367        if (c == null || c.isZERO()) {
368            return Cp;
369        }
370        ResidueSolvablePolynomial<C> Cb = new ResidueSolvablePolynomial<C>(ring, b, ring.evzero);
371        ResidueSolvablePolynomial<C> Cc = new ResidueSolvablePolynomial<C>(ring, c, ring.evzero);
372        return Cb.multiply(this).multiply(Cc);
373    }
374
375
376    /**
377     * ResidueSolvablePolynomial multiplication. Product with exponent vector.
378     * @param e exponent.
379     * @return this * x<sup>e</sup>, where * denotes solvable multiplication.
380     */
381    @Override
382    public ResidueSolvablePolynomial<C> multiply(ExpVector e) {
383        if (e == null || e.isZERO()) {
384            return this;
385        }
386        SolvableResidue<C> b = ring.getONECoefficient();
387        return multiply(b, e);
388    }
389
390
391    /**
392     * ResidueSolvablePolynomial left and right multiplication. Product with
393     * exponent vector.
394     * @param e exponent.
395     * @param f exponent.
396     * @return x<sup>e</sup> * this * x<sup>f</sup>, where * denotes solvable
397     *         multiplication.
398     */
399    @Override
400    public ResidueSolvablePolynomial<C> multiply(ExpVector e, ExpVector f) {
401        if (e == null || e.isZERO()) {
402            return this;
403        }
404        if (f == null || f.isZERO()) {
405            return this;
406        }
407        SolvableResidue<C> b = ring.getONECoefficient();
408        return multiply(b, e, b, f);
409    }
410
411
412    /**
413     * ResidueSolvablePolynomial multiplication. Product with ring element and
414     * exponent vector.
415     * @param b coefficient polynomial.
416     * @param e exponent.
417     * @return this * b x<sup>e</sup>, where * denotes solvable multiplication.
418     */
419    @Override
420    public ResidueSolvablePolynomial<C> multiply(SolvableResidue<C> b, ExpVector e) {
421        if (b == null || b.isZERO()) {
422            return ring.getZERO();
423        }
424        ResidueSolvablePolynomial<C> Cp = new ResidueSolvablePolynomial<C>(ring, b, e);
425        return multiply(Cp);
426    }
427
428
429    /**
430     * ResidueSolvablePolynomial left and right multiplication. Product with
431     * ring element and exponent vector.
432     * @param b coefficient polynomial.
433     * @param e exponent.
434     * @param c coefficient polynomial.
435     * @param f exponent.
436     * @return b x<sup>e</sup> * this * c x<sup>f</sup>, where * denotes
437     *         solvable multiplication.
438     */
439    @Override
440    public ResidueSolvablePolynomial<C> multiply(SolvableResidue<C> b, ExpVector e, SolvableResidue<C> c,
441                    ExpVector f) {
442        if (b == null || b.isZERO()) {
443            return ring.getZERO();
444        }
445        if (c == null || c.isZERO()) {
446            return ring.getZERO();
447        }
448        ResidueSolvablePolynomial<C> Cp = new ResidueSolvablePolynomial<C>(ring, b, e);
449        ResidueSolvablePolynomial<C> Dp = new ResidueSolvablePolynomial<C>(ring, c, f);
450        return multiply(Cp, Dp);
451    }
452
453
454    /**
455     * ResidueSolvablePolynomial multiplication. Left product with ring element
456     * and exponent vector.
457     * @param b coefficient polynomial.
458     * @param e exponent.
459     * @return b x<sup>e</sup> * this, where * denotes solvable multiplication.
460     */
461    @Override
462    public ResidueSolvablePolynomial<C> multiplyLeft(SolvableResidue<C> b, ExpVector e) {
463        if (b == null || b.isZERO()) {
464            return ring.getZERO();
465        }
466        ResidueSolvablePolynomial<C> Cp = new ResidueSolvablePolynomial<C>(ring, b, e);
467        return Cp.multiply(this);
468    }
469
470
471    /**
472     * ResidueSolvablePolynomial multiplication. Left product with exponent
473     * vector.
474     * @param e exponent.
475     * @return x<sup>e</sup> * this, where * denotes solvable multiplication.
476     */
477    @Override
478    public ResidueSolvablePolynomial<C> multiplyLeft(ExpVector e) {
479        if (e == null || e.isZERO()) {
480            return this;
481        }
482        SolvableResidue<C> b = ring.getONECoefficient();
483        ResidueSolvablePolynomial<C> Cp = new ResidueSolvablePolynomial<C>(ring, b, e);
484        return Cp.multiply(this);
485    }
486
487
488    /**
489     * ResidueSolvablePolynomial multiplication. Left product with coefficient
490     * ring element.
491     * @param b coefficient polynomial.
492     * @return b*this, where * is coefficient multiplication.
493     */
494    @Override
495    public ResidueSolvablePolynomial<C> multiplyLeft(SolvableResidue<C> b) {
496        ResidueSolvablePolynomial<C> Cp = ring.getZERO().copy();
497        if (b == null || b.isZERO()) {
498            return Cp;
499        }
500        Map<ExpVector, SolvableResidue<C>> Cm = Cp.val; //getMap();
501        Map<ExpVector, SolvableResidue<C>> Am = val;
502        SolvableResidue<C> c;
503        for (Map.Entry<ExpVector, SolvableResidue<C>> y : Am.entrySet()) {
504            ExpVector e = y.getKey();
505            SolvableResidue<C> a = y.getValue();
506            c = b.multiply(a);
507            if (!c.isZERO()) {
508                Cm.put(e, c);
509            }
510        }
511        return Cp;
512    }
513
514
515    /**
516     * ResidueSolvablePolynomial multiplication. Left product with 'monomial'.
517     * @param m 'monomial'.
518     * @return m * this, where * denotes solvable multiplication.
519     */
520    @Override
521    public ResidueSolvablePolynomial<C> multiplyLeft(Map.Entry<ExpVector, SolvableResidue<C>> m) {
522        if (m == null) {
523            return ring.getZERO();
524        }
525        return multiplyLeft(m.getValue(), m.getKey());
526    }
527
528
529    /**
530     * ResidueSolvablePolynomial multiplication. Product with 'monomial'.
531     * @param m 'monomial'.
532     * @return this * m, where * denotes solvable multiplication.
533     */
534    @Override
535    public ResidueSolvablePolynomial<C> multiply(Map.Entry<ExpVector, SolvableResidue<C>> m) {
536        if (m == null) {
537            return ring.getZERO();
538        }
539        return multiply(m.getValue(), m.getKey());
540    }
541
542
543    /**
544     * ResidueSolvablePolynomial multiplication with exponent vector.
545     * @param f exponent vector.
546     * @return B*f, where * is commutative multiplication.
547     */
548    protected ResidueSolvablePolynomial<C> shift(ExpVector f) {
549        ResidueSolvablePolynomial<C> C = ring.getZERO().copy();
550        if (this.isZERO()) {
551            return C;
552        }
553        if (f == null || f.isZERO()) {
554            return this;
555        }
556        Map<ExpVector, SolvableResidue<C>> Cm = C.val;
557        Map<ExpVector, SolvableResidue<C>> Bm = this.val;
558        for (Map.Entry<ExpVector, SolvableResidue<C>> y : Bm.entrySet()) {
559            ExpVector e = y.getKey();
560            SolvableResidue<C> a = y.getValue();
561            ExpVector d = e.sum(f);
562            if (!a.isZERO()) {
563                Cm.put(d, a);
564            }
565        }
566        return C;
567    }
568
569}