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        logger.debug("ring = {}", ring);
174        ExpVector Z = ring.evzero;
175        ResidueSolvablePolynomial<C> Dp = ring.getZERO().copy();
176        ResidueSolvablePolynomial<C> zero = ring.getZERO().copy();
177        SolvableResidue<C> one = ring.getONECoefficient();
178
179        //ResidueSolvablePolynomial<C> C1 = null;
180        //ResidueSolvablePolynomial<C> C2 = null;
181        Map<ExpVector, SolvableResidue<C>> A = val;
182        Map<ExpVector, SolvableResidue<C>> B = Bp.val;
183        Set<Map.Entry<ExpVector, SolvableResidue<C>>> Bk = B.entrySet();
184        for (Map.Entry<ExpVector, SolvableResidue<C>> y : A.entrySet()) {
185            SolvableResidue<C> a = y.getValue();
186            ExpVector e = y.getKey();
187            if (debug)
188                logger.info("e = {}, a = {}", e, a);
189            //int[] ep = e.dependencyOnVariables();
190            //int el1 = ring.nvar + 1;
191            //if (ep.length > 0) {
192            //    el1 = ep[0];
193            //}
194            //int el1s = ring.nvar + 1 - el1;
195            for (Map.Entry<ExpVector, SolvableResidue<C>> x : Bk) {
196                SolvableResidue<C> b = x.getValue();
197                ExpVector f = x.getKey();
198                if (debug)
199                    logger.info("f = {}, b = {}", f, b);
200                int[] fp = f.dependencyOnVariables();
201                int fl1 = 0;
202                if (fp.length > 0) {
203                    fl1 = fp[fp.length - 1];
204                }
205                int fl1s = ring.nvar + 1 - fl1;
206                // polynomial coefficient multiplication 
207                ResidueSolvablePolynomial<C> Cps = ring.getZERO().copy();
208                //ResidueSolvablePolynomial<C> Cs = null;
209                if (ring.polCoeff.coeffTable.isEmpty() || b.isConstant() || e.isZERO()) { // symmetric
210                    Cps = new ResidueSolvablePolynomial<C>(ring, b, e);
211                    if (debug)
212                        logger.info("symmetric coeff: b = {}, e = {}", b, e);
213                } else { // unsymmetric
214                    if (debug)
215                        logger.info("unsymmetric coeff: b = {}, e = {}", b, e);
216                    // recursive polynomial coefficient multiplication : e * b.val
217                    RecSolvablePolynomial<C> rsp1 = new RecSolvablePolynomial<C>(ring.polCoeff, e);
218                    RecSolvablePolynomial<C> rsp2 = new RecSolvablePolynomial<C>(ring.polCoeff, b.val);
219                    RecSolvablePolynomial<C> rsp3 = rsp1.multiply(rsp2);
220                    Cps = ring.fromPolyCoefficients(rsp3);
221                }
222                if (debug) {
223                    logger.info("coeff-poly: Cps = {}", Cps);
224                }
225                // polynomial multiplication 
226                ResidueSolvablePolynomial<C> Dps = ring.getZERO().copy();
227                ResidueSolvablePolynomial<C> Ds = null;
228                ResidueSolvablePolynomial<C> D1, D2;
229                if (ring.table.isEmpty() || Cps.isConstant() || f.isZERO()) { // symmetric
230                    if (debug)
231                        logger.info("symmetric poly: b = {}, e = {}", b, e);
232                    ExpVector g = e.sum(f);
233                    if (Cps.isConstant()) {
234                        Ds = new ResidueSolvablePolynomial<C>(ring, Cps.leadingBaseCoefficient(), g); // symmetric!
235                    } else {
236                        Ds = Cps.shift(f); // symmetric
237                    }
238                } else { // eventually unsymmetric
239                    if (debug)
240                        logger.info("unsymmetric poly: Cps = {}, f = {}", Cps, f);
241                    for (Map.Entry<ExpVector, SolvableResidue<C>> z : Cps.val.entrySet()) {
242                        // split g = g1 * g2, f = f1 * f2
243                        SolvableResidue<C> c = z.getValue();
244                        ExpVector g = z.getKey();
245                        if (debug)
246                            logger.info("g = {}, c = {}", g, c);
247                        int[] gp = g.dependencyOnVariables();
248                        int gl1 = ring.nvar + 1;
249                        if (gp.length > 0) {
250                            gl1 = gp[0];
251                        }
252                        int gl1s = ring.nvar + 1 - gl1;
253                        if (gl1s <= fl1s) { // symmetric
254                            ExpVector h = g.sum(f);
255                            if (debug)
256                                logger.info("disjoint poly: g = {}, f = {}, h = {}", g, f, h);
257                            Ds = (ResidueSolvablePolynomial<C>) zero.sum(one, h); // symmetric!
258                        } else {
259                            ExpVector g1 = g.subst(gl1, 0);
260                            ExpVector g2 = Z.subst(gl1, g.getVal(gl1)); // bug el1, gl1
261                            ExpVector g4;
262                            ExpVector f1 = f.subst(fl1, 0);
263                            ExpVector f2 = Z.subst(fl1, f.getVal(fl1));
264                            if (debug)
265                                logger.info("poly, g1 = {}, f1 = {}, Dps = {}", g1, f1, Dps);
266                            if (debug)
267                                logger.info("poly, g2 = {}, f2 = {}", g2, f2);
268                            TableRelation<SolvableResidue<C>> rel = ring.table.lookup(g2, f2);
269                            if (debug)
270                                logger.info("poly, g  = {}, f  = {}, rel = {}", g, f, rel);
271                            Ds = new ResidueSolvablePolynomial<C>(ring, rel.p); //ring.copy(rel.p);
272                            if (rel.f != null) {
273                                D2 = new ResidueSolvablePolynomial<C>(ring, one, rel.f);
274                                Ds = Ds.multiply(D2);
275                                if (rel.e == null) {
276                                    g4 = g2;
277                                } else {
278                                    g4 = g2.subtract(rel.e);
279                                }
280                                ring.table.update(g4, f2, Ds);
281                            }
282                            if (rel.e != null) {
283                                D1 = new ResidueSolvablePolynomial<C>(ring, one, rel.e);
284                                Ds = D1.multiply(Ds);
285                                ring.table.update(g2, f2, Ds);
286                            }
287                            if (!f1.isZERO()) {
288                                D2 = new ResidueSolvablePolynomial<C>(ring, one, f1);
289                                Ds = Ds.multiply(D2);
290                                //ring.table.update(?,f1,Ds)
291                            }
292                            if (!g1.isZERO()) {
293                                D1 = new ResidueSolvablePolynomial<C>(ring, one, g1);
294                                Ds = D1.multiply(Ds);
295                                //ring.table.update(e1,?,Ds)
296                            }
297                        }
298                        Ds = Ds.multiplyLeft(c); // assume c commutes with Cs
299                        Dps = (ResidueSolvablePolynomial<C>) Dps.sum(Ds);
300                    } // end Dps loop
301                    Ds = Dps;
302                }
303                Ds = Ds.multiplyLeft(a); // multiply(a,b); // non-symmetric 
304                logger.debug("Ds = {}", Ds);
305                Dp = (ResidueSolvablePolynomial<C>) Dp.sum(Ds);
306            } // end B loop
307        } // end A loop
308        return Dp;
309    }
310
311
312    /**
313     * ResidueSolvablePolynomial left and right multiplication. Product with two
314     * polynomials.
315     * @param S ResidueSolvablePolynomial.
316     * @param T ResidueSolvablePolynomial.
317     * @return S*this*T.
318     */
319    public ResidueSolvablePolynomial<C> multiply(ResidueSolvablePolynomial<C> S,
320                    ResidueSolvablePolynomial<C> T) {
321        if (S.isZERO() || T.isZERO() || this.isZERO()) {
322            return ring.getZERO();
323        }
324        if (S.isONE()) {
325            return multiply(T);
326        }
327        if (T.isONE()) {
328            return S.multiply(this);
329        }
330        return S.multiply(this).multiply(T);
331    }
332
333
334    /**
335     * ResidueSolvablePolynomial multiplication. Product with coefficient ring
336     * element.
337     * @param b coefficient polynomial.
338     * @return this*b, where * is coefficient multiplication.
339     */
340    @Override
341    public ResidueSolvablePolynomial<C> multiply(SolvableResidue<C> b) {
342        ResidueSolvablePolynomial<C> Cp = ring.getZERO().copy();
343        if (b == null || b.isZERO()) {
344            return Cp;
345        }
346        Cp = new ResidueSolvablePolynomial<C>(ring, b, ring.evzero);
347        return multiply(Cp);
348    }
349
350
351    /**
352     * ResidueSolvablePolynomial left and right multiplication. Product with
353     * coefficient ring element.
354     * @param b coefficient polynomial.
355     * @param c coefficient polynomial.
356     * @return b*this*c, where * is coefficient multiplication.
357     */
358    @Override
359    public ResidueSolvablePolynomial<C> multiply(SolvableResidue<C> b, SolvableResidue<C> c) {
360        ResidueSolvablePolynomial<C> Cp = ring.getZERO().copy();
361        if (b == null || b.isZERO()) {
362            return Cp;
363        }
364        if (c == null || c.isZERO()) {
365            return Cp;
366        }
367        ResidueSolvablePolynomial<C> Cb = new ResidueSolvablePolynomial<C>(ring, b, ring.evzero);
368        ResidueSolvablePolynomial<C> Cc = new ResidueSolvablePolynomial<C>(ring, c, ring.evzero);
369        return Cb.multiply(this).multiply(Cc);
370    }
371
372
373    /**
374     * ResidueSolvablePolynomial multiplication. Product with exponent vector.
375     * @param e exponent.
376     * @return this * x<sup>e</sup>, where * denotes solvable multiplication.
377     */
378    @Override
379    public ResidueSolvablePolynomial<C> multiply(ExpVector e) {
380        if (e == null || e.isZERO()) {
381            return this;
382        }
383        SolvableResidue<C> b = ring.getONECoefficient();
384        return multiply(b, e);
385    }
386
387
388    /**
389     * ResidueSolvablePolynomial left and right multiplication. Product with
390     * exponent vector.
391     * @param e exponent.
392     * @param f exponent.
393     * @return x<sup>e</sup> * this * x<sup>f</sup>, where * denotes solvable
394     *         multiplication.
395     */
396    @Override
397    public ResidueSolvablePolynomial<C> multiply(ExpVector e, ExpVector f) {
398        if (e == null || e.isZERO()) {
399            return this;
400        }
401        if (f == null || f.isZERO()) {
402            return this;
403        }
404        SolvableResidue<C> b = ring.getONECoefficient();
405        return multiply(b, e, b, f);
406    }
407
408
409    /**
410     * ResidueSolvablePolynomial multiplication. Product with ring element and
411     * exponent vector.
412     * @param b coefficient polynomial.
413     * @param e exponent.
414     * @return this * b x<sup>e</sup>, where * denotes solvable multiplication.
415     */
416    @Override
417    public ResidueSolvablePolynomial<C> multiply(SolvableResidue<C> b, ExpVector e) {
418        if (b == null || b.isZERO()) {
419            return ring.getZERO();
420        }
421        ResidueSolvablePolynomial<C> Cp = new ResidueSolvablePolynomial<C>(ring, b, e);
422        return multiply(Cp);
423    }
424
425
426    /**
427     * ResidueSolvablePolynomial left and right multiplication. Product with
428     * ring element and exponent vector.
429     * @param b coefficient polynomial.
430     * @param e exponent.
431     * @param c coefficient polynomial.
432     * @param f exponent.
433     * @return b x<sup>e</sup> * this * c x<sup>f</sup>, where * denotes
434     *         solvable multiplication.
435     */
436    @Override
437    public ResidueSolvablePolynomial<C> multiply(SolvableResidue<C> b, ExpVector e, SolvableResidue<C> c,
438                    ExpVector f) {
439        if (b == null || b.isZERO()) {
440            return ring.getZERO();
441        }
442        if (c == null || c.isZERO()) {
443            return ring.getZERO();
444        }
445        ResidueSolvablePolynomial<C> Cp = new ResidueSolvablePolynomial<C>(ring, b, e);
446        ResidueSolvablePolynomial<C> Dp = new ResidueSolvablePolynomial<C>(ring, c, f);
447        return multiply(Cp, Dp);
448    }
449
450
451    /**
452     * ResidueSolvablePolynomial multiplication. Left product with ring element
453     * and exponent vector.
454     * @param b coefficient polynomial.
455     * @param e exponent.
456     * @return b x<sup>e</sup> * this, where * denotes solvable multiplication.
457     */
458    @Override
459    public ResidueSolvablePolynomial<C> multiplyLeft(SolvableResidue<C> b, ExpVector e) {
460        if (b == null || b.isZERO()) {
461            return ring.getZERO();
462        }
463        ResidueSolvablePolynomial<C> Cp = new ResidueSolvablePolynomial<C>(ring, b, e);
464        return Cp.multiply(this);
465    }
466
467
468    /**
469     * ResidueSolvablePolynomial multiplication. Left product with exponent
470     * vector.
471     * @param e exponent.
472     * @return x<sup>e</sup> * this, where * denotes solvable multiplication.
473     */
474    @Override
475    public ResidueSolvablePolynomial<C> multiplyLeft(ExpVector e) {
476        if (e == null || e.isZERO()) {
477            return this;
478        }
479        SolvableResidue<C> b = ring.getONECoefficient();
480        ResidueSolvablePolynomial<C> Cp = new ResidueSolvablePolynomial<C>(ring, b, e);
481        return Cp.multiply(this);
482    }
483
484
485    /**
486     * ResidueSolvablePolynomial multiplication. Left product with coefficient
487     * ring element.
488     * @param b coefficient polynomial.
489     * @return b*this, where * is coefficient multiplication.
490     */
491    @Override
492    public ResidueSolvablePolynomial<C> multiplyLeft(SolvableResidue<C> b) {
493        ResidueSolvablePolynomial<C> Cp = ring.getZERO().copy();
494        if (b == null || b.isZERO()) {
495            return Cp;
496        }
497        Map<ExpVector, SolvableResidue<C>> Cm = Cp.val; //getMap();
498        Map<ExpVector, SolvableResidue<C>> Am = val;
499        SolvableResidue<C> c;
500        for (Map.Entry<ExpVector, SolvableResidue<C>> y : Am.entrySet()) {
501            ExpVector e = y.getKey();
502            SolvableResidue<C> a = y.getValue();
503            c = b.multiply(a);
504            if (!c.isZERO()) {
505                Cm.put(e, c);
506            }
507        }
508        return Cp;
509    }
510
511
512    /**
513     * ResidueSolvablePolynomial multiplication. Left product with 'monomial'.
514     * @param m 'monomial'.
515     * @return m * this, where * denotes solvable multiplication.
516     */
517    @Override
518    public ResidueSolvablePolynomial<C> multiplyLeft(Map.Entry<ExpVector, SolvableResidue<C>> m) {
519        if (m == null) {
520            return ring.getZERO();
521        }
522        return multiplyLeft(m.getValue(), m.getKey());
523    }
524
525
526    /**
527     * ResidueSolvablePolynomial multiplication. Product with 'monomial'.
528     * @param m 'monomial'.
529     * @return this * m, where * denotes solvable multiplication.
530     */
531    @Override
532    public ResidueSolvablePolynomial<C> multiply(Map.Entry<ExpVector, SolvableResidue<C>> m) {
533        if (m == null) {
534            return ring.getZERO();
535        }
536        return multiply(m.getValue(), m.getKey());
537    }
538
539
540    /**
541     * ResidueSolvablePolynomial multiplication with exponent vector.
542     * @param f exponent vector.
543     * @return B*f, where * is commutative multiplication.
544     */
545    protected ResidueSolvablePolynomial<C> shift(ExpVector f) {
546        ResidueSolvablePolynomial<C> C = ring.getZERO().copy();
547        if (this.isZERO()) {
548            return C;
549        }
550        if (f == null || f.isZERO()) {
551            return this;
552        }
553        Map<ExpVector, SolvableResidue<C>> Cm = C.val;
554        Map<ExpVector, SolvableResidue<C>> Bm = this.val;
555        for (Map.Entry<ExpVector, SolvableResidue<C>> y : Bm.entrySet()) {
556            ExpVector e = y.getKey();
557            SolvableResidue<C> a = y.getValue();
558            ExpVector d = e.sum(f);
559            if (!a.isZERO()) {
560                Cm.put(d, a);
561            }
562        }
563        return C;
564    }
565
566}