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