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