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