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.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 = {}, 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>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 = {}, c = {}", g, c);
443                    throw new RuntimeException("g==h: a = " + a + ", ap = " + ap);
444                }
445            }
446        }
447        logger.info("multiplicative factor = {}", mfac);
448        pf = new PseudoReductionEntry<C>(R, mfac);
449        return pf;
450    }
451
452
453    /**
454     * Right normalform.
455     * @param Ap polynomial.
456     * @param Pp polynomial list.
457     * @return nf(Ap) with respect to Pp. 
458     */
459    @SuppressWarnings({ "unchecked" })
460    public GenSolvablePolynomial<C> rightNormalform(List<GenSolvablePolynomial<C>> Pp,
461                    GenSolvablePolynomial<C> Ap) {
462        if (Pp == null || Pp.isEmpty()) {
463            return Ap;
464        }
465        if (Ap == null || Ap.isZERO()) {
466            return Ap;
467        }
468        Map.Entry<ExpVector, C> m;
469        GenSolvablePolynomial<C>[] P = new GenSolvablePolynomial[0];
470        synchronized (Pp) {
471            P = Pp.toArray(P);
472        }
473        int l = P.length;
474        ExpVector[] htl = new ExpVector[l];
475        //C[] lbc = (C[]) new GcdRingElem[l];
476        GenSolvablePolynomial<C>[] p = new GenSolvablePolynomial[l];
477        int i;
478        int j = 0;
479        for (i = 0; i < l; i++) {
480            if (P[i] == null) {
481                continue;
482            }
483            p[i] = P[i];
484            m = p[i].leadingMonomial();
485            if (m != null) {
486                p[j] = p[i];
487                htl[j] = m.getKey();
488                //lbc[j] = m.getValue();
489                j++;
490            }
491        }
492        l = j;
493        ExpVector e;
494        C a;
495        boolean mt = false;
496        GenSolvablePolynomial<C> R = Ap.ring.getZERO().copy();
497        GenSolvablePolynomial<C> Q = null;
498        GenSolvablePolynomial<C> S = Ap.copy();
499        while (S.length() > 0) {
500            m = S.leadingMonomial();
501            e = m.getKey();
502            a = m.getValue();
503            for (i = 0; i < l; i++) {
504                mt = e.multipleOf(htl[i]);
505                if (mt)
506                    break;
507            }
508            if (!mt) {
509                //logger.debug("irred");
510                //R = R.sum(a, e);
511                //S = S.subtract(a, e);
512                R.doPutToMap(e, a);
513                S.doRemoveFromMap(e, a);
514                //System.out.println(" S = " + S);
515            } else {
516                e = e.subtract(htl[i]);
517                //logger.info("red div = {}", e);
518                // need pi * a * e, but only pi * e * a or a * pi * e available
519                Q = p[i].multiply(e);
520                assert Q.multiply(a).equals(Q.multiplyLeft(a));
521                C c = Q.leadingBaseCoefficient();
522                ExpVector g = S.leadingExpVector();
523                C ap = a;
524                if (a.remainder(c).isZERO()) {
525                    a = a.divide(c); // left?
526                    //S = S.subtractMultiple(Q,a);
527                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
528                } else {
529                    R = R.multiply(c);
530                    S = S.multiply(c);
531                    //S = S.scaleSubtractMultiple(c, Q, a);
532                    S = (GenSolvablePolynomial<C>) S.subtract(Q.multiply(a));
533                }
534                ExpVector h = S.leadingExpVector();
535                if (g.equals(h)) { // Ore condition not fulfilled
536                    logger.info("g==h: g = {}, c = {}", g, c);
537                    throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap);
538                }
539            }
540        }
541        //System.out.println("R = " + R);
542        return R;
543    }
544
545
546    /**
547     * Right normalform recursive.
548     * @param Ap recursive polynomial.
549     * @param Pp recursive polynomial list.
550     * @return nf(Ap) with respect to Pp. <b>Note: </b> not implemented;
551     */
552    public GenSolvablePolynomial<GenPolynomial<C>> rightNormalformRecursive(
553                    List<GenSolvablePolynomial<GenPolynomial<C>>> Pp,
554                    GenSolvablePolynomial<GenPolynomial<C>> Ap) {
555        if (Pp == null || Ap == null) {
556            throw new IllegalArgumentException("Pp or Ap == null not supported");
557        }
558        throw new UnsupportedOperationException(); // TODO
559    }
560
561
562    /**
563     * Left normalform with recording. <b>Note:</b> Only meaningful if all
564     * divisions are exact. Compute first the multiplication factor
565     * <code>m</code> with <code>normalform(Pp,Ap,m)</code>, then call this
566     * method with <code>normalform(row,Pp,m*Ap)</code>.
567     * @param row recording matrix, is modified.
568     * @param Pp a polynomial list for reduction.
569     * @param Ap a polynomial.
570     * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. <b>Note: </b> not
571     *         implemented;
572     */
573    public GenSolvablePolynomial<C> rightNormalform(List<GenSolvablePolynomial<C>> row,
574                    List<GenSolvablePolynomial<C>> Pp, GenSolvablePolynomial<C> Ap) {
575        if (row == null || Pp == null || Ap == null) {
576            throw new IllegalArgumentException("row, Pp or Ap == null not supported");
577        }
578        throw new UnsupportedOperationException(); // TODO
579    }
580
581
582    /**
583     * Right normalform with multiplication factor.
584     * @param Pp polynomial list.
585     * @param Ap polynomial.
586     * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor
587     *         for Ap. <b>Note: </b> not implemented;
588     */
589    public PseudoReductionEntry<C> rightNormalformFactor(List<GenSolvablePolynomial<C>> Pp,
590                    GenSolvablePolynomial<C> Ap) {
591        if (Pp == null || Ap == null) {
592            throw new IllegalArgumentException("Pp or Ap == null not supported");
593        }
594        throw new UnsupportedOperationException(); // TODO
595    }
596
597}