001/*
002 * $Id$
003 */
004
005package edu.jas.gbufd;
006
007
008import java.util.List;
009import java.util.Map;
010
011import org.apache.logging.log4j.LogManager;
012import org.apache.logging.log4j.Logger;
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 = {}, c = {}", g, 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>mf</code> with <code>(nf,mf) = normalformfactor(Pp,Ap)</code>, then
258     * call this method with <code>normalform(row,Pp,mf*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 (row == null || Pp == null || Ap == null) {
268            throw new IllegalArgumentException("row, Pp or Ap == null not supported");
269        }
270        if (Pp.isEmpty()) {
271            return Ap;
272        }
273        if (Ap.isZERO()) {
274            return Ap;
275        }
276        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
277        synchronized (Pp) {
278            P = Pp.toArray(P);
279        }
280        int l = P.length;
281        ExpVector[] htl = new ExpVector[l];
282        //C[] lbc = (C[]) new GcdRingElem[l];
283        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
284        Map.Entry<ExpVector, C> m;
285        int j = 0;
286        int i;
287        for (i = 0; i < l; i++) {
288            p[i] = P[i];
289            m = p[i].leadingMonomial();
290            if (m != null) {
291                p[j] = p[i];
292                htl[j] = m.getKey();
293                //lbc[j] = m.getValue();
294                j++;
295            }
296        }
297        l = j;
298        ExpVector e;
299        C a;
300        boolean mt = false;
301        GenSolvablePolynomial<C> zero = Ap.ring.getZERO();
302        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
303        GenSolvablePolynomial<C> Q = null;
304        GenSolvablePolynomial<C> fac = null;
305        GenSolvablePolynomial<C> S = Ap.copy();
306        while (S.length() > 0) {
307            m = S.leadingMonomial();
308            e = m.getKey();
309            a = m.getValue();
310            for (i = 0; i < l; i++) {
311                mt = e.multipleOf(htl[i]);
312                if (mt)
313                    break;
314            }
315            if (!mt) {
316                //logger.debug("irred");
317                //R = R.sum(a, e);
318                //S = S.subtract(a, e);
319                R.doPutToMap(e, a);
320                S.doRemoveFromMap(e, a);
321                // System.out.println(" S = " + S);
322                //throw new RuntimeException("Syzygy no GB");
323            } else {
324                e = e.subtract(htl[i]);
325                //logger.info("red div = {}", e);
326                Q = p[i].multiplyLeft(e);
327                C c = Q.leadingBaseCoefficient();
328                ExpVector g = S.leadingExpVector();
329                C ap = a;
330                if (a.remainder(c).isZERO()) { //c.isUnit() ) {
331                    a = a.divide(c);
332                    S = S.subtractMultiple(a, Q);
333                    //System.out.print("|");
334                } else {
335                    //System.out.print("*");
336                    R = R.multiplyLeft(c);
337                    S = S.scaleSubtractMultiple(c, a, Q);
338                }
339                ExpVector h = S.leadingExpVector();
340                if (g.equals(h)) { // Ore condition not fulfilled
341                    System.out.println("g = " + g + ", h = " + h);
342                    System.out.println("c*ap = " + c.multiply(ap) + ", ap*c = " + ap.multiply(c));
343                    throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap + ", c = " + c);
344                }
345                //Q = p[i].multiply(a, e);
346                //S = S.subtract(Q);
347                fac = row.get(i);
348                if (fac == null) {
349                    fac = (GenSolvablePolynomial<C>) zero.sum(a, e);
350                } else { // doAddTo ??
351                    fac = (GenSolvablePolynomial<C>) fac.sum(a, e);
352                }
353                row.set(i, fac);
354            }
355        }
356        return R;
357    }
358
359
360    /**
361     * Left normalform with factor.
362     * @param Pp polynomial list.
363     * @param Ap polynomial.
364     * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor
365     *         for Ap.
366     */
367    @SuppressWarnings("unchecked")
368    public PseudoReductionEntry<C> leftNormalformFactor(List<GenSolvablePolynomial<C>> Pp,
369                    GenSolvablePolynomial<C> Ap) {
370        if (Ap == null) {
371            return null;
372        }
373        C mfactor = Ap.ring.getONECoefficient();
374        PseudoReductionEntry<C> pf = new PseudoReductionEntry<C>(Ap, mfactor);
375        if (Pp == null || Pp.isEmpty()) {
376            return pf;
377        }
378        if (Ap.isZERO()) {
379            return pf;
380        }
381        Map.Entry<ExpVector, C> m;
382        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
383        synchronized (Pp) {
384            P = Pp.toArray(P);
385        }
386        int l = P.length;
387        ExpVector[] htl = new ExpVector[l];
388        //C[] lbc = (C[]) new GcdRingElem[l]; 
389        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
390        int i;
391        int j = 0;
392        for (i = 0; i < l; i++) {
393            if (P[i] == null) {
394                continue;
395            }
396            p[i] = P[i];
397            m = p[i].leadingMonomial();
398            if (m != null) {
399                p[j] = p[i];
400                htl[j] = m.getKey();
401                //lbc[j] = m.getValue();
402                j++;
403            }
404        }
405        l = j;
406        ExpVector e;
407        C a;
408        boolean mt = false;
409        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
410        GenSolvablePolynomial<C> Q = null;
411        GenSolvablePolynomial<C> S = Ap.copy();
412        while (S.length() > 0) {
413            m = S.leadingMonomial();
414            e = m.getKey();
415            a = m.getValue();
416            for (i = 0; i < l; i++) {
417                mt = e.multipleOf(htl[i]);
418                if (mt)
419                    break;
420            }
421            if (!mt) {
422                //logger.debug("irred");
423                //R = R.sum(a, e);
424                //S = S.subtract(a, e);
425                R.doPutToMap(e, a);
426                S.doRemoveFromMap(e, a);
427                //System.out.println(" S = " + S);
428            } else {
429                e = e.subtract(htl[i]);
430                //logger.info("red div = {}", e);
431                Q = p[i].multiplyLeft(e);
432                C c = Q.leadingBaseCoefficient();
433                ExpVector g = S.leadingExpVector();
434                C ap = a;
435                if (a.remainder(c).isZERO()) {
436                    a = a.divide(c);
437                    S = S.subtractMultiple(a, Q);
438                } else {
439                    mfactor = c.multiply(mfactor); // left
440                    R = R.multiplyLeft(c);
441                    S = S.scaleSubtractMultiple(c, a, Q);
442                }
443                ExpVector h = S.leadingExpVector();
444                if (g.equals(h)) { // Ore condition not fulfilled
445                    logger.info("g==h: g = {}, c = {}", g, c);
446                    throw new RuntimeException("g==h: a = " + a + ", ap = " + ap);
447                }
448            }
449        }
450        logger.info("multiplicative factor = {}", mfactor);
451        pf = new PseudoReductionEntry<C>(R, mfactor);
452        return pf;
453    }
454
455
456    /**
457     * Right normalform.
458     * @param Ap polynomial.
459     * @param Pp polynomial list.
460     * @return nf(Ap) with respect to Pp.
461     */
462    @SuppressWarnings("unchecked")
463    public GenSolvablePolynomial<C> rightNormalform(List<GenSolvablePolynomial<C>> Pp,
464                    GenSolvablePolynomial<C> Ap) {
465        if (Pp == null || Pp.isEmpty()) {
466            return Ap;
467        }
468        if (Ap == null || Ap.isZERO()) {
469            return Ap;
470        }
471        Map.Entry<ExpVector, C> m;
472        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
473        synchronized (Pp) {
474            P = Pp.toArray(P);
475        }
476        int l = P.length;
477        ExpVector[] htl = new ExpVector[l];
478        //C[] lbc = (C[]) new GcdRingElem[l];
479        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
480        int i;
481        int j = 0;
482        for (i = 0; i < l; i++) {
483            if (P[i] == null) {
484                continue;
485            }
486            p[i] = P[i];
487            m = p[i].leadingMonomial();
488            if (m != null) {
489                p[j] = p[i];
490                htl[j] = m.getKey();
491                //lbc[j] = m.getValue();
492                j++;
493            }
494        }
495        l = j;
496        ExpVector e;
497        C a;
498        boolean mt = false;
499        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
500        GenSolvablePolynomial<C> Q = null;
501        GenSolvablePolynomial<C> S = Ap.copy();
502        while (S.length() > 0) {
503            m = S.leadingMonomial();
504            e = m.getKey();
505            a = m.getValue();
506            for (i = 0; i < l; i++) {
507                mt = e.multipleOf(htl[i]);
508                if (mt)
509                    break;
510            }
511            if (!mt) {
512                //logger.debug("irred");
513                //R = R.sum(a, e);
514                //S = S.subtract(a, e);
515                R.doPutToMap(e, a);
516                S.doRemoveFromMap(e, a);
517                //System.out.println(" S = " + S);
518            } else {
519                e = e.subtract(htl[i]);
520                //logger.info("red div = {}", e);
521                // need pi * a * e, but only pi * e * a or a * pi * e available
522                Q = p[i].multiply(e);
523                assert Q.multiply(a).equals(Q.multiplyLeft(a));
524                C c = Q.leadingBaseCoefficient();
525                ExpVector g = S.leadingExpVector();
526                C ap = a;
527                if (a.remainder(c).isZERO()) {
528                    a = a.divide(c); // left?
529                    //S = S.subtractMultiple(Q,a);
530                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
531                } else {
532                    R = R.multiply(c);
533                    //S = S.scaleSubtractMultiple(c, Q, a);
534                    S = S.multiply(c);
535                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
536                }
537                ExpVector h = S.leadingExpVector();
538                if (g.equals(h)) { // Ore condition not fulfilled
539                    logger.info("g==h: g = {}, c = {}", g, c);
540                    throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap);
541                }
542            }
543        }
544        //System.out.println("R = " + R);
545        return R;
546    }
547
548
549    /**
550     * Right normalform recursive.
551     * @param Ap recursive polynomial.
552     * @param Pp recursive polynomial list.
553     * @return nf(Ap) with respect to Pp. <!--b>Note: not implemented;</b-->
554     */
555    @SuppressWarnings("unchecked")
556    public GenSolvablePolynomial<GenPolynomial<C>> rightNormalformRecursive(
557                    List<GenSolvablePolynomial<GenPolynomial<C>>> Pp,
558                    GenSolvablePolynomial<GenPolynomial<C>> Ap) {
559        if (Pp == null || Ap == null) {
560            throw new IllegalArgumentException("Pp or Ap == null not supported");
561        }
562        //throw new UnsupportedOperationException();
563        if (Pp.isEmpty()) {
564            return Ap;
565        }
566        if (Ap.isZERO()) {
567            return Ap;
568        }
569        Map.Entry<ExpVector, GenPolynomial<C>> m;
570        GenSolvablePolynomial<GenPolynomial<C>>[] P = new GenSolvablePolynomial[0];
571        synchronized (Pp) {
572            P = Pp.toArray(P);
573        }
574        int l = P.length;
575        ExpVector[] htl = new ExpVector[l];
576        //GenPolynomial<C>[] lbc = (GenPolynomial<C>[]) new GenPolynomial[l];
577        GenSolvablePolynomial<GenPolynomial<C>>[] p = new GenSolvablePolynomial[l];
578        int i;
579        int j = 0;
580        for (i = 0; i < l; i++) {
581            if (P[i] == null) {
582                continue;
583            }
584            p[i] = P[i];
585            m = p[i].leadingMonomial();
586            if (m != null) {
587                p[j] = p[i];
588                htl[j] = m.getKey();
589                //lbc[j] = m.getValue();
590                j++;
591            }
592        }
593        l = j;
594        ExpVector e, f;
595        GenPolynomial<C> a, b;
596        boolean mt = false;
597        GenSolvablePolynomialRing<GenPolynomial<C>> ring = Ap.ring;
598        final boolean commCoeff = ring.coFac.isCommutative();
599        final SolvableSyzygyAbstract<C> ssy;
600        if (commCoeff) {
601            ssy = null;
602        } else {
603            ssy = new SolvableSyzygySeq<C>(((GenPolynomialRing<C>) ring.coFac).coFac);
604        }
605        GenSolvablePolynomial<GenPolynomial<C>> R = Ap.ring.getZERO().copy();
606        GenSolvablePolynomial<GenPolynomial<C>> Q = null;
607        GenSolvablePolynomial<GenPolynomial<C>> S = Ap.copy();
608        //GenSolvablePolynomial<GenPolynomial<C>> Sp = null;
609        while (S.length() > 0) {
610            m = S.leadingMonomial();
611            e = m.getKey();
612            a = m.getValue();
613            for (i = 0; i < l; i++) {
614                mt = e.multipleOf(htl[i]);
615                if (mt)
616                    break;
617            }
618            if (!mt) {
619                //logger.debug("irred");
620                //R = R.sum(a, e);
621                //S = S.subtract(a, e);
622                R.doPutToMap(e, a);
623                S.doRemoveFromMap(e, a);
624                //System.out.println(" S = " + S);
625            } else {
626                f = e.subtract(htl[i]);
627                if (debug) {
628                    logger.info("red div = {}", f);
629                    //logger.info("red a = {}", a);
630                }
631                // need pi * a * e, but only pi * e * a or a * pi * e available
632                Q = p[i].multiply(f);
633                assert Q.multiply(a).equals(Q.multiplyLeft(a));
634                ExpVector g = S.leadingExpVector();
635                GenPolynomial<C> ap = a;
636                if (commCoeff) {
637                    GenPolynomial<C> c = Q.leadingBaseCoefficient();
638                    if (!c.isConstant() && PolyUtil.<C> baseSparsePseudoRemainder(a, c).isZERO()) {
639                        //a = a.divide(c);
640                        b = PolyUtil.<C> basePseudoDivide(a, c);
641                        if (a.equals(b.multiply(c))) {
642                            //S = S.subtractMultiple(b, Q);
643                            S = (GenSolvablePolynomial<GenPolynomial<C>>) S.subtract(Q.multiply(b));
644                        } else {
645                            R = R.multiply(c);
646                            //S = S.scaleSubtractMultiple(c, a, Q);
647                            S = S.multiply(c);
648                            S = (GenSolvablePolynomial<GenPolynomial<C>>) S.subtract(Q.multiply(a));
649                        }
650                    } else {
651                        R = R.multiply(c);
652                        //S = S.scaleSubtractMultiple(c, a, Q);
653                        S = S.multiply(c);
654                        S = (GenSolvablePolynomial<GenPolynomial<C>>) S.subtract(Q.multiply(a));
655                    }
656                } else { // use Ore condition
657                    GenSolvablePolynomial<C> cs = (GenSolvablePolynomial<C>) Q.leadingBaseCoefficient();
658                    GenSolvablePolynomial<C> as = (GenSolvablePolynomial<C>) a;
659                    GenPolynomial<C>[] ore = ssy.rightOreCond(cs, as);
660                    //System.out.println("cs = " + cs + ", as = " + as);
661                    //System.out.println("ore[0] = " + ore[0] + "\nore[1] = " + ore[1]);
662                    R = R.multiply(ore[1]);
663                    //S = S.scaleSubtractMultiple(ore[1], ore[0], Q);
664                    S = S.multiply(ore[1]);
665                    S = (GenSolvablePolynomial<GenPolynomial<C>>) S.subtract(Q.multiply(ore[0]));
666                }
667                ExpVector h = S.leadingExpVector();
668                if (g.equals(h)) { // Ore condition not fulfilled
669                    logger.info("not Ore: g==h: g = {}", g);
670                    throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap);
671                }
672            }
673        }
674        //System.out.println("Ap = " + Ap + ", R = " + R);
675        return R;
676    }
677
678
679    /**
680     * Right normalform with recording. <b>Note:</b> Only meaningful if all
681     * divisions are exact. Compute first the multiplication factor
682     * <code>mf</code> with <code>(nf, mf) =
683     * normalformfactor(Pp,Ap)</code>, then call this method with
684     * <code>normalform(row,Pp,mf*Ap)</code>.
685     * @param row recording matrix, is modified.
686     * @param Pp a polynomial list for reduction.
687     * @param Ap a polynomial.
688     * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. <!--b>Note: </b> not
689     *         implemented; </b-->
690     */
691    @SuppressWarnings("unchecked")
692    public GenSolvablePolynomial<C> rightNormalform(List<GenSolvablePolynomial<C>> row,
693                    List<GenSolvablePolynomial<C>> Pp, GenSolvablePolynomial<C> Ap) {
694        if (row == null || Pp == null || Ap == null) {
695            throw new IllegalArgumentException("row, Pp or Ap == null not supported");
696        }
697        //throw new UnsupportedOperationException();
698        if (Pp.isEmpty()) {
699            return Ap;
700        }
701        if (Ap.isZERO()) {
702            return Ap;
703        }
704        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
705        synchronized (Pp) {
706            P = Pp.toArray(P);
707        }
708        int l = P.length;
709        ExpVector[] htl = new ExpVector[l];
710        //C[] lbc = (C[]) new GcdRingElem[l];
711        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
712        Map.Entry<ExpVector, C> m;
713        int j = 0;
714        int i;
715        for (i = 0; i < l; i++) {
716            p[i] = P[i];
717            m = p[i].leadingMonomial();
718            if (m != null) {
719                p[j] = p[i];
720                htl[j] = m.getKey();
721                //lbc[j] = m.getValue();
722                j++;
723            }
724        }
725        l = j;
726        ExpVector e;
727        C a;
728        boolean mt = false;
729        GenSolvablePolynomial<C> zero = Ap.ring.getZERO();
730        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
731        GenSolvablePolynomial<C> Q = null;
732        GenSolvablePolynomial<C> fac = null;
733        GenSolvablePolynomial<C> S = Ap.copy();
734        while (S.length() > 0) {
735            m = S.leadingMonomial();
736            e = m.getKey();
737            a = m.getValue();
738            for (i = 0; i < l; i++) {
739                mt = e.multipleOf(htl[i]);
740                if (mt)
741                    break;
742            }
743            if (!mt) {
744                //logger.debug("irred");
745                //R = R.sum(a, e);
746                //S = S.subtract(a, e);
747                R.doPutToMap(e, a);
748                S.doRemoveFromMap(e, a);
749                // System.out.println(" S = " + S);
750                //throw new RuntimeException("Syzygy no GB");
751            } else {
752                e = e.subtract(htl[i]);
753                //logger.info("red div = {}", e);
754                Q = p[i].multiply(e);
755                assert Q.multiply(a).equals(Q.multiplyLeft(a));
756                C c = Q.leadingBaseCoefficient();
757                ExpVector g = S.leadingExpVector();
758                C ap = a;
759                if (a.remainder(c).isZERO()) { //c.isUnit() ) {
760                    a = a.divide(c);
761                    //S = S.subtractMultiple(a, Q);
762                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
763                    //System.out.print("|");
764                } else {
765                    //System.out.print("*");
766                    R = R.multiply(c);
767                    //S = S.scaleSubtractMultiple(c, a, Q);
768                    S = S.multiply(c);
769                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
770                }
771                ExpVector h = S.leadingExpVector();
772                if (g.equals(h)) { // Ore condition not fulfilled
773                    logger.info("no Ore: g==h: g = {}, c = {}", g, c);
774                    System.out.println("c*ap = " + c.multiply(ap) + ", ap*c = " + ap.multiply(c));
775                    throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap + ", c = " + c);
776                }
777                //Q = p[i].multiply(a, e);
778                //S = S.subtract(Q);
779                fac = row.get(i);
780                if (fac == null) {
781                    fac = (GenSolvablePolynomial<C>) zero.sum(a, e);
782                } else { // doAddTo ??
783                    fac = (GenSolvablePolynomial<C>) fac.sum(a, e);
784                }
785                row.set(i, fac);
786            }
787        }
788        return R;
789    }
790
791
792    /**
793     * Right normalform with multiplication factor.
794     * @param Pp polynomial list.
795     * @param Ap polynomial.
796     * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor
797     *         for Ap. <!--b>Note: not implemented; </b-->
798     */
799    @SuppressWarnings("unchecked")
800    public PseudoReductionEntry<C> rightNormalformFactor(List<GenSolvablePolynomial<C>> Pp,
801                    GenSolvablePolynomial<C> Ap) {
802        //throw new UnsupportedOperationException();
803        if (Ap == null) {
804            throw new IllegalArgumentException("Ap == null not supported");
805            //return null;
806        }
807        C mfactor = Ap.ring.getONECoefficient();
808        PseudoReductionEntry<C> pf = new PseudoReductionEntry<C>(Ap, mfactor);
809        if (Pp == null || Pp.isEmpty()) {
810            return pf;
811        }
812        if (Ap.isZERO()) {
813            return pf;
814        }
815        Map.Entry<ExpVector, C> m;
816        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
817        synchronized (Pp) {
818            P = Pp.toArray(P);
819        }
820        int l = P.length;
821        ExpVector[] htl = new ExpVector[l];
822        //C[] lbc = (C[]) new GcdRingElem[l];
823        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
824        int i;
825        int j = 0;
826        for (i = 0; i < l; i++) {
827            if (P[i] == null) {
828                continue;
829            }
830            p[i] = P[i];
831            m = p[i].leadingMonomial();
832            if (m != null) {
833                p[j] = p[i];
834                htl[j] = m.getKey();
835                //lbc[j] = m.getValue();
836                j++;
837            }
838        }
839        l = j;
840        ExpVector e;
841        C a;
842        boolean mt = false;
843        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
844        GenSolvablePolynomial<C> Q = null;
845        GenSolvablePolynomial<C> S = Ap.copy();
846        while (S.length() > 0) {
847            m = S.leadingMonomial();
848            e = m.getKey();
849            a = m.getValue();
850            for (i = 0; i < l; i++) {
851                mt = e.multipleOf(htl[i]);
852                if (mt)
853                    break;
854            }
855            if (!mt) {
856                //logger.debug("irred");
857                //R = R.sum(a, e);
858                //S = S.subtract(a, e);
859                R.doPutToMap(e, a);
860                S.doRemoveFromMap(e, a);
861                //System.out.println(" S = " + S);
862            } else {
863                e = e.subtract(htl[i]);
864                //logger.info("red div = {}", e);
865                Q = p[i].multiply(e);
866                assert Q.multiply(a).equals(Q.multiplyLeft(a));
867                C c = Q.leadingBaseCoefficient();
868                ExpVector g = S.leadingExpVector();
869                C ap = a;
870                if (a.remainder(c).isZERO()) {
871                    a = a.divide(c);
872                    //S = S.subtractMultiple(a, Q);
873                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
874                } else {
875                    mfactor = mfactor.multiply(c); // right
876                    R = R.multiply(c);
877                    //S = S.scaleSubtractMultiple(c, a, Q);
878                    S = S.multiply(c);
879                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
880                }
881                ExpVector h = S.leadingExpVector();
882                if (g.equals(h)) { // Ore condition not fulfilled
883                    logger.info("no Ore: g==h: g = {}, c = {}", g, c);
884                    throw new RuntimeException("g==h: a = " + a + ", ap = " + ap);
885                }
886            }
887        }
888        logger.info("multiplicative factor = {}", mfactor);
889        pf = new PseudoReductionEntry<C>(R, mfactor);
890        return pf;
891    }
892
893}