001/*
002 * $Id: SolvablePseudoReductionSeq.java 5870 2018-07-20 15:56:23Z kredel $
003 */
004
005package edu.jas.gbufd;
006
007
008import java.util.List;
009import java.util.Map;
010
011import org.apache.logging.log4j.Logger;
012import org.apache.logging.log4j.LogManager; 
013
014import edu.jas.gb.SolvableReductionAbstract;
015import edu.jas.poly.ExpVector;
016import edu.jas.poly.GenPolynomial;
017import edu.jas.poly.GenPolynomialRing;
018import edu.jas.poly.GenSolvablePolynomial;
019import edu.jas.poly.GenSolvablePolynomialRing;
020import edu.jas.poly.PolyUtil;
021import edu.jas.structure.GcdRingElem;
022
023
024/**
025 * Polynomial pseudo reduction sequential use algorithm. Coefficients of
026 * polynomials must not be from a field, i.e. the fraction free reduction is
027 * implemented. Implements normalform.
028 * @param <C> coefficient type
029 * @author Heinz Kredel
030 */
031
032public class SolvablePseudoReductionSeq<C extends GcdRingElem<C>> extends SolvableReductionAbstract<C>
033                implements SolvablePseudoReduction<C> {
034
035
036    private static final Logger logger = LogManager.getLogger(SolvablePseudoReductionSeq.class);
037
038
039    private static final boolean debug = logger.isDebugEnabled();
040
041
042    /**
043     * Constructor.
044     */
045    public SolvablePseudoReductionSeq() {
046    }
047
048
049    /**
050     * Left normalform.
051     * @param Ap polynomial.
052     * @param Pp polynomial list.
053     * @return nf(Ap) with respect to Pp.
054     */
055    @SuppressWarnings("unchecked")
056    public GenSolvablePolynomial<C> leftNormalform(List<GenSolvablePolynomial<C>> Pp,
057                    GenSolvablePolynomial<C> Ap) {
058        if (Pp == null || Pp.isEmpty()) {
059            return Ap;
060        }
061        if (Ap == null || Ap.isZERO()) {
062            return Ap;
063        }
064        Map.Entry<ExpVector, C> m;
065        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
066        synchronized (Pp) {
067            P = Pp.toArray(P);
068        }
069        int l = P.length;
070        ExpVector[] htl = new ExpVector[l];
071        //C[] lbc = (C[]) new GcdRingElem[l];
072        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
073        int i;
074        int j = 0;
075        for (i = 0; i < l; i++) {
076            if (P[i] == null) {
077                continue;
078            }
079            p[i] = P[i];
080            m = p[i].leadingMonomial();
081            if (m != null) {
082                p[j] = p[i];
083                htl[j] = m.getKey();
084                //lbc[j] = m.getValue();
085                j++;
086            }
087        }
088        l = j;
089        ExpVector e;
090        C a;
091        boolean mt = false;
092        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
093        GenSolvablePolynomial<C> Q = null;
094        GenSolvablePolynomial<C> S = Ap.copy();
095        while (S.length() > 0) {
096            m = S.leadingMonomial();
097            e = m.getKey();
098            a = m.getValue();
099            for (i = 0; i < l; i++) {
100                mt = e.multipleOf(htl[i]);
101                if (mt)
102                    break;
103            }
104            if (!mt) {
105                //logger.debug("irred");
106                //R = R.sum(a, e);
107                //S = S.subtract(a, e);
108                R.doPutToMap(e, a);
109                S.doRemoveFromMap(e, a);
110                //System.out.println(" S = " + S);
111            } else {
112                e = e.subtract(htl[i]);
113                //logger.info("red div = " + e);
114                Q = p[i].multiplyLeft(e);
115                C c = Q.leadingBaseCoefficient();
116                ExpVector g = S.leadingExpVector();
117                C ap = a;
118                if (a.remainder(c).isZERO()) { // && !c.isConstant()) {
119                    a = a.divide(c);
120                    S = S.subtractMultiple(a, Q);
121                } else {
122                    R = R.multiplyLeft(c);
123                    S = S.scaleSubtractMultiple(c, a, Q);
124                }
125                ExpVector h = S.leadingExpVector();
126                if (g.equals(h)) { // Ore condition not fulfilled
127                    logger.info("g==h: g = " + g + ", c = " + c);
128                    throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap + ", c = " + c);
129                }
130            }
131        }
132        return R;
133    }
134
135
136    /**
137     * Left normalform recursive.
138     * @param Ap recursive polynomial.
139     * @param Pp recursive polynomial list.
140     * @return nf(Ap) with respect to Pp.
141     */
142    @SuppressWarnings({ "unchecked" })
143    public GenSolvablePolynomial<GenPolynomial<C>> leftNormalformRecursive(
144                    List<GenSolvablePolynomial<GenPolynomial<C>>> Pp,
145                    GenSolvablePolynomial<GenPolynomial<C>> Ap) {
146        if (Pp == null || Pp.isEmpty()) {
147            return Ap;
148        }
149        if (Ap == null || Ap.isZERO()) {
150            return Ap;
151        }
152        Map.Entry<ExpVector, GenPolynomial<C>> m;
153        GenSolvablePolynomial<GenPolynomial<C>>[] P = new GenSolvablePolynomial[0];
154        synchronized (Pp) {
155            P = Pp.toArray(P);
156        }
157        int l = P.length;
158        ExpVector[] htl = new ExpVector[l];
159        //GenPolynomial<C>[] lbc = (GenPolynomial<C>[]) new GenPolynomial[l];
160        GenSolvablePolynomial<GenPolynomial<C>>[] p = new GenSolvablePolynomial[l];
161        int i;
162        int j = 0;
163        for (i = 0; i < l; i++) {
164            if (P[i] == null) {
165                continue;
166            }
167            p[i] = P[i];
168            m = p[i].leadingMonomial();
169            if (m != null) {
170                p[j] = p[i];
171                htl[j] = m.getKey();
172                //lbc[j] = m.getValue();
173                j++;
174            }
175        }
176        l = j;
177        ExpVector e, f;
178        GenPolynomial<C> a, b;
179        boolean mt = false;
180        GenSolvablePolynomialRing<GenPolynomial<C>> ring = Ap.ring;
181        final boolean commCoeff = ring.coFac.isCommutative();
182        final SolvableSyzygyAbstract<C> ssy;
183        if (commCoeff) {
184            ssy = null;
185        } else {
186            ssy = new SolvableSyzygySeq<C>(((GenPolynomialRing<C>) ring.coFac).coFac);
187        }
188        GenSolvablePolynomial<GenPolynomial<C>> R = Ap.ring.getZERO().copy();
189        GenSolvablePolynomial<GenPolynomial<C>> Q = null;
190        GenSolvablePolynomial<GenPolynomial<C>> S = Ap.copy();
191        //GenSolvablePolynomial<GenPolynomial<C>> Sp = null;
192        while (S.length() > 0) {
193            m = S.leadingMonomial();
194            e = m.getKey();
195            a = m.getValue();
196            for (i = 0; i < l; i++) {
197                mt = e.multipleOf(htl[i]);
198                if (mt)
199                    break;
200            }
201            if (!mt) {
202                //logger.debug("irred");
203                //R = R.sum(a, e);
204                //S = S.subtract(a, e);
205                R.doPutToMap(e, a);
206                S.doRemoveFromMap(e, a);
207                //System.out.println(" S = " + S);
208            } else {
209                f = e.subtract(htl[i]);
210                if (debug) {
211                    logger.info("red div = " + f);
212                    //logger.info("red a = " + a);
213                }
214                Q = p[i].multiplyLeft(f);
215                //if (a.remainder(c).isZERO()) { //c.isUnit() ) {
216                ExpVector g = S.leadingExpVector();
217                GenPolynomial<C> ap = a;
218                if (commCoeff) {
219                    GenPolynomial<C> c = Q.leadingBaseCoefficient();
220                    if (!c.isConstant() && PolyUtil.<C> baseSparsePseudoRemainder(a, c).isZERO()) {
221                        //a = a.divide(c);
222                        b = PolyUtil.<C> basePseudoDivide(a, c);
223                        if (a.equals(b.multiply(c))) {
224                            S = S.subtractMultiple(b, Q);
225                        } else {
226                            R = R.multiplyLeft(c);
227                            S = S.scaleSubtractMultiple(c, a, Q);
228                        }
229                    } else {
230                        R = R.multiplyLeft(c);
231                        S = S.scaleSubtractMultiple(c, a, Q);
232                    }
233                } else { // use Ore condition
234                    GenSolvablePolynomial<C> cs = (GenSolvablePolynomial<C>) Q.leadingBaseCoefficient();
235                    GenSolvablePolynomial<C> as = (GenSolvablePolynomial<C>) a;
236                    GenPolynomial<C>[] ore = ssy.leftOreCond(cs, as);
237                    //System.out.println("cs = " + cs + ", as = " + as);
238                    //System.out.println("ore[0] = " + ore[0] + "\nore[1] = " + ore[1]);
239                    R = R.multiplyLeft(ore[1]);
240                    S = S.scaleSubtractMultiple(ore[1], ore[0], Q);
241                }
242                ExpVector h = S.leadingExpVector();
243                if (g.equals(h)) { // ! Ore cond
244                    logger.info("g==h: g = " + g);
245                    throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap);
246                }
247            }
248        }
249        //System.out.println("Ap = " + Ap + ", R = " + R);
250        return R;
251    }
252
253
254    /**
255     * Left normalform with recording. <b>Note:</b> Only meaningful if all
256     * divisions are exact. Compute first the multiplication factor
257     * <code>m</code> with <code>normalform(Pp,Ap,m)</code>, then call this
258     * method with <code>normalform(row,Pp,m*Ap)</code>.
259     * @param row recording matrix, is modified.
260     * @param Pp a polynomial list for reduction.
261     * @param Ap a polynomial.
262     * @return nf(Pp,Ap), the normal form of Ap wrt. Pp.
263     */
264    @SuppressWarnings("unchecked")
265    public GenSolvablePolynomial<C> leftNormalform(List<GenSolvablePolynomial<C>> row,
266                    List<GenSolvablePolynomial<C>> Pp, GenSolvablePolynomial<C> Ap) {
267        if (Pp == null || Pp.isEmpty()) {
268            return Ap;
269        }
270        if (Ap == null || Ap.isZERO()) {
271            return Ap;
272        }
273        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
274        synchronized (Pp) {
275            P = Pp.toArray(P);
276        }
277        int l = P.length;
278        ExpVector[] htl = new ExpVector[l];
279        //C[] lbc = (C[]) new GcdRingElem[l];
280        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
281        Map.Entry<ExpVector, C> m;
282        int j = 0;
283        int i;
284        for (i = 0; i < l; i++) {
285            p[i] = P[i];
286            m = p[i].leadingMonomial();
287            if (m != null) {
288                p[j] = p[i];
289                htl[j] = m.getKey();
290                //lbc[j] = m.getValue();
291                j++;
292            }
293        }
294        l = j;
295        ExpVector e;
296        C a;
297        boolean mt = false;
298        GenSolvablePolynomial<C> zero = Ap.ring.getZERO();
299        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
300        GenSolvablePolynomial<C> Q = null;
301        GenSolvablePolynomial<C> fac = null;
302        GenSolvablePolynomial<C> S = Ap.copy();
303        while (S.length() > 0) {
304            m = S.leadingMonomial();
305            e = m.getKey();
306            a = m.getValue();
307            for (i = 0; i < l; i++) {
308                mt = e.multipleOf(htl[i]);
309                if (mt)
310                    break;
311            }
312            if (!mt) {
313                //logger.debug("irred");
314                //R = R.sum(a, e);
315                //S = S.subtract(a, e);
316                R.doPutToMap(e, a);
317                S.doRemoveFromMap(e, a);
318                // System.out.println(" S = " + S);
319                //throw new RuntimeException("Syzygy no GB");
320            } else {
321                e = e.subtract(htl[i]);
322                //logger.info("red div = " + e);
323                Q = p[i].multiplyLeft(e);
324                C c = Q.leadingBaseCoefficient();
325                ExpVector g = S.leadingExpVector();
326                C ap = a;
327                if (a.remainder(c).isZERO()) { //c.isUnit() ) {
328                    a = a.divide(c);
329                    S = S.subtractMultiple(a, Q);
330                    //System.out.print("|");
331                } else {
332                    //System.out.print("*");
333                    R = R.multiplyLeft(c);
334                    S = S.scaleSubtractMultiple(c, a, Q);
335                }
336                ExpVector h = S.leadingExpVector();
337                if (g.equals(h)) { // Ore condition not fulfilled
338                    System.out.println("g = " + g + ", h = " + h);
339                    System.out.println("c*ap = " + c.multiply(ap) + ", ap*c = " + ap.multiply(c));
340                    throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap + ", c = " + c);
341                }
342                //Q = p[i].multiply(a, e);
343                //S = S.subtract(Q);
344                fac = row.get(i);
345                if (fac == null) {
346                    fac = (GenSolvablePolynomial<C>) zero.sum(a, e);
347                } else { // doAddTo ??
348                    fac = (GenSolvablePolynomial<C>) fac.sum(a, e);
349                }
350                row.set(i, fac);
351            }
352        }
353        return R;
354    }
355
356
357    /**
358     * Left normalform with factor.
359     * @param Pp polynomial list.
360     * @param Ap polynomial.
361     * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor
362     *         for Ap.
363     */
364    @SuppressWarnings("unchecked")
365    public PseudoReductionEntry<C> leftNormalformFactor(List<GenSolvablePolynomial<C>> Pp,
366                    GenSolvablePolynomial<C> Ap) {
367        if (Ap == null) {
368            return null;
369        }
370        C mfac = Ap.ring.getONECoefficient();
371        PseudoReductionEntry<C> pf = new PseudoReductionEntry<C>(Ap, mfac);
372        if (Pp == null || Pp.isEmpty()) {
373            return pf;
374        }
375        if (Ap.isZERO()) {
376            return pf;
377        }
378        Map.Entry<ExpVector, C> m;
379        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
380        synchronized (Pp) {
381            P = Pp.toArray(P);
382        }
383        int l = P.length;
384        ExpVector[] htl = new ExpVector[l];
385        //C[] lbc = (C[]) new GcdRingElem[l]; 
386        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
387        int i;
388        int j = 0;
389        for (i = 0; i < l; i++) {
390            if (P[i] == null) {
391                continue;
392            }
393            p[i] = P[i];
394            m = p[i].leadingMonomial();
395            if (m != null) {
396                p[j] = p[i];
397                htl[j] = m.getKey();
398                //lbc[j] = m.getValue();
399                j++;
400            }
401        }
402        l = j;
403        ExpVector e;
404        C a;
405        boolean mt = false;
406        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
407        GenSolvablePolynomial<C> Q = null;
408        GenSolvablePolynomial<C> S = Ap.copy();
409        while (S.length() > 0) {
410            m = S.leadingMonomial();
411            e = m.getKey();
412            a = m.getValue();
413            for (i = 0; i < l; i++) {
414                mt = e.multipleOf(htl[i]);
415                if (mt)
416                    break;
417            }
418            if (!mt) {
419                //logger.debug("irred");
420                //R = R.sum(a, e);
421                //S = S.subtract(a, e);
422                R.doPutToMap(e, a);
423                S.doRemoveFromMap(e, a);
424                //System.out.println(" S = " + S);
425            } else {
426                e = e.subtract(htl[i]);
427                //logger.info("red div = " + e);
428                Q = p[i].multiplyLeft(e);
429                C c = Q.leadingBaseCoefficient();
430                ExpVector g = S.leadingExpVector();
431                C ap = a;
432                if (a.remainder(c).isZERO()) {
433                    a = a.divide(c);
434                    S = S.subtractMultiple(a, Q);
435                } else {
436                    mfac = c.multiply(mfac); // left
437                    R = R.multiplyLeft(c);
438                    S = S.scaleSubtractMultiple(c, a, Q);
439                }
440                ExpVector h = S.leadingExpVector();
441                if (g.equals(h)) { // Ore condition not fulfilled
442                    logger.info("g==h: g = " + g + ", c = " + c);
443                    throw new RuntimeException("g==h: a = " + a + ", ap = " + ap);
444                }
445            }
446        }
447        if (logger.isDebugEnabled()) {
448            logger.info("multiplicative factor = " + mfac);
449        }
450        pf = new PseudoReductionEntry<C>(R, mfac);
451        return pf;
452    }
453
454
455    /**
456     * Right normalform.
457     * @param Ap polynomial.
458     * @param Pp polynomial list.
459     * @return nf(Ap) with respect to Pp. 
460     */
461    @SuppressWarnings({ "unchecked" })
462    public GenSolvablePolynomial<C> rightNormalform(List<GenSolvablePolynomial<C>> Pp,
463                    GenSolvablePolynomial<C> Ap) {
464        if (Pp == null || Pp.isEmpty()) {
465            return Ap;
466        }
467        if (Ap == null || Ap.isZERO()) {
468            return Ap;
469        }
470        Map.Entry<ExpVector, C> m;
471        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
472        synchronized (Pp) {
473            P = Pp.toArray(P);
474        }
475        int l = P.length;
476        ExpVector[] htl = new ExpVector[l];
477        //C[] lbc = (C[]) new GcdRingElem[l];
478        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
479        int i;
480        int j = 0;
481        for (i = 0; i < l; i++) {
482            if (P[i] == null) {
483                continue;
484            }
485            p[i] = P[i];
486            m = p[i].leadingMonomial();
487            if (m != null) {
488                p[j] = p[i];
489                htl[j] = m.getKey();
490                //lbc[j] = m.getValue();
491                j++;
492            }
493        }
494        l = j;
495        ExpVector e;
496        C a;
497        boolean mt = false;
498        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
499        GenSolvablePolynomial<C> Q = null;
500        GenSolvablePolynomial<C> S = Ap.copy();
501        while (S.length() > 0) {
502            m = S.leadingMonomial();
503            e = m.getKey();
504            a = m.getValue();
505            for (i = 0; i < l; i++) {
506                mt = e.multipleOf(htl[i]);
507                if (mt)
508                    break;
509            }
510            if (!mt) {
511                //logger.debug("irred");
512                //R = R.sum(a, e);
513                //S = S.subtract(a, e);
514                R.doPutToMap(e, a);
515                S.doRemoveFromMap(e, a);
516                //System.out.println(" S = " + S);
517            } else {
518                e = e.subtract(htl[i]);
519                //logger.info("red div = " + e);
520                // need pi * a * e, but only pi * e * a or a * pi * e available
521                Q = p[i].multiply(e);
522                assert Q.multiply(a).equals(Q.multiplyLeft(a));
523                C c = Q.leadingBaseCoefficient();
524                ExpVector g = S.leadingExpVector();
525                C ap = a;
526                if (a.remainder(c).isZERO()) {
527                    a = a.divide(c); // left?
528                    //S = S.subtractMultiple(Q,a);
529                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
530                } else {
531                    R = R.multiply(c);
532                    S = S.multiply(c);
533                    //S = S.scaleSubtractMultiple(c, Q, a);
534                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
535                }
536                ExpVector h = S.leadingExpVector();
537                if (g.equals(h)) { // Ore condition not fulfilled
538                    logger.info("g==h: g = " + g + ", c = " + c);
539                    throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap);
540                }
541            }
542        }
543        //System.out.println("R = " + R);
544        return R;
545    }
546
547
548    /**
549     * Right normalform recursive.
550     * @param Ap recursive polynomial.
551     * @param Pp recursive polynomial list.
552     * @return nf(Ap) with respect to Pp. <b>Note: </b> not implemented;
553     */
554    public GenSolvablePolynomial<GenPolynomial<C>> rightNormalformRecursive(
555                    List<GenSolvablePolynomial<GenPolynomial<C>>> Pp,
556                    GenSolvablePolynomial<GenPolynomial<C>> Ap) {
557        if (Pp == null || Ap == null) {
558            throw new IllegalArgumentException("Pp or Ap == null not supported");
559        }
560        throw new UnsupportedOperationException(); // TODO
561    }
562
563
564    /**
565     * Left normalform with recording. <b>Note:</b> Only meaningful if all
566     * divisions are exact. Compute first the multiplication factor
567     * <code>m</code> with <code>normalform(Pp,Ap,m)</code>, then call this
568     * method with <code>normalform(row,Pp,m*Ap)</code>.
569     * @param row recording matrix, is modified.
570     * @param Pp a polynomial list for reduction.
571     * @param Ap a polynomial.
572     * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. <b>Note: </b> not
573     *         implemented;
574     */
575    public GenSolvablePolynomial<C> rightNormalform(List<GenSolvablePolynomial<C>> row,
576                    List<GenSolvablePolynomial<C>> Pp, GenSolvablePolynomial<C> Ap) {
577        if (row == null || Pp == null || Ap == null) {
578            throw new IllegalArgumentException("row, Pp or Ap == null not supported");
579        }
580        throw new UnsupportedOperationException(); // TODO
581    }
582
583
584    /**
585     * Right normalform with multiplication factor.
586     * @param Pp polynomial list.
587     * @param Ap polynomial.
588     * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor
589     *         for Ap. <b>Note: </b> not implemented;
590     */
591    public PseudoReductionEntry<C> rightNormalformFactor(List<GenSolvablePolynomial<C>> Pp,
592                    GenSolvablePolynomial<C> Ap) {
593        if (Pp == null || Ap == null) {
594            throw new IllegalArgumentException("Pp or Ap == null not supported");
595        }
596        throw new UnsupportedOperationException(); // TODO
597    }
598
599}