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