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