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