001/*
002 * $Id$
003 */
004
005package edu.jas.poly;
006
007
008import java.io.BufferedReader;
009import java.io.IOException;
010import java.io.InputStreamReader;
011import java.io.Reader;
012import java.io.StreamTokenizer;
013import java.nio.charset.Charset;
014import java.util.ArrayList;
015import java.util.Arrays;
016import java.util.Iterator;
017import java.util.List;
018import java.util.Scanner;
019import java.util.Set;
020import java.util.TreeSet;
021
022import org.apache.logging.log4j.LogManager;
023import org.apache.logging.log4j.Logger;
024
025import edu.jas.arith.BigComplex;
026import edu.jas.arith.BigDecimal;
027import edu.jas.arith.BigInteger;
028import edu.jas.arith.BigOctonion;
029import edu.jas.arith.BigQuaternion;
030import edu.jas.arith.BigQuaternionRing;
031import edu.jas.arith.BigRational;
032import edu.jas.arith.ModIntRing;
033import edu.jas.arith.ModInteger;
034import edu.jas.arith.ModIntegerRing;
035import edu.jas.arith.ModLongRing;
036import edu.jas.structure.RingElem;
037import edu.jas.structure.RingFactory;
038
039
040/**
041 * GenPolynomial Tokenizer. Used to read rational polynomials and lists of
042 * polynomials from input streams. Arbitrary polynomial rings and coefficient
043 * rings can be read with RingFactoryTokenizer. <b>Note:</b> Can no more read
044 * QuotientRing since end of 2010, revision 3441. Quotient coefficients and
045 * others can still be read if the respective factory is provided via the
046 * constructor.
047 * @see edu.jas.application.RingFactoryTokenizer
048 * @author Heinz Kredel
049 */
050public class GenPolynomialTokenizer {
051
052
053    private static final Logger logger = LogManager.getLogger(GenPolynomialTokenizer.class);
054
055
056    private static final boolean debug = logger.isDebugEnabled();
057
058
059    private String[] vars;
060
061
062    private int nvars = 1;
063
064
065    private TermOrder tord;
066
067
068    private RelationTable table;
069
070
071    private final StreamTokenizer tok;
072
073
074    private final Reader reader;
075
076
077    private RingFactory fac;
078
079
080    private static enum coeffType {
081        BigRat, BigInt, ModInt, BigC, BigQ, BigO, BigD, ANrat, ANmod, IntFunc
082    };
083
084
085    private coeffType parsedCoeff = coeffType.BigRat;
086
087
088    private GenPolynomialRing pfac;
089
090
091    private static enum polyType {
092        PolBigRat, PolBigInt, PolModInt, PolBigC, PolBigD, PolBigQ, PolBigO, PolANrat, PolANmod, PolIntFunc
093    };
094
095
096    @SuppressWarnings("unused")
097    private polyType parsedPoly = polyType.PolBigRat;
098
099
100    private GenSolvablePolynomialRing spfac;
101
102
103    /**
104     * No-args constructor reads from System.in.
105     */
106    public GenPolynomialTokenizer() {
107        this(new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF8"))));
108    }
109
110
111    /**
112     * Constructor with Ring and Reader.
113     * @param rf ring factory.
114     * @param r reader stream.
115     */
116    public GenPolynomialTokenizer(GenPolynomialRing rf, Reader r) {
117        this(r);
118        if (rf == null) {
119            return;
120        }
121        if (rf instanceof GenSolvablePolynomialRing) {
122            pfac = rf;
123            spfac = (GenSolvablePolynomialRing) rf;
124        } else {
125            pfac = rf;
126            spfac = null;
127        }
128        fac = rf.coFac;
129        vars = rf.vars;
130        if (vars != null) {
131            nvars = vars.length;
132        }
133        tord = rf.tord;
134        // relation table
135        if (spfac != null) {
136            table = spfac.table;
137        } else {
138            table = null;
139        }
140    }
141
142
143    /**
144     * Constructor with Reader.
145     * @param r reader stream.
146     */
147    @SuppressWarnings("unchecked")
148    public GenPolynomialTokenizer(Reader r) {
149        vars = null;
150        tord = new TermOrder();
151        nvars = 1;
152        fac = new BigRational(1);
153
154        pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars);
155        spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars);
156
157        reader = r;
158        tok = new StreamTokenizer(reader);
159        tok.resetSyntax();
160        // tok.eolIsSignificant(true); no more
161        tok.eolIsSignificant(false);
162        tok.wordChars('0', '9');
163        tok.wordChars('a', 'z');
164        tok.wordChars('A', 'Z');
165        tok.wordChars('_', '_'); // for subscripts x_i
166        tok.wordChars('/', '/'); // wg. rational numbers
167        tok.wordChars('.', '.'); // wg. floats
168        tok.wordChars('~', '~'); // wg. quaternions
169        tok.wordChars(128 + 32, 255);
170        tok.whitespaceChars(0, ' ');
171        tok.commentChar('#');
172        tok.quoteChar('"');
173        tok.quoteChar('\'');
174        //tok.slashStarComments(true); does not work
175
176    }
177
178
179    /**
180     * Initialize coefficient and polynomial factories.
181     * @param rf ring factory.
182     * @param ct coefficient type.
183     */
184    @SuppressWarnings("unchecked")
185    public void initFactory(RingFactory rf, coeffType ct) {
186        fac = rf;
187        parsedCoeff = ct;
188
189        switch (ct) {
190        case BigRat:
191            pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars);
192            parsedPoly = polyType.PolBigRat;
193            break;
194        case BigInt:
195            pfac = new GenPolynomialRing<BigInteger>(fac, nvars, tord, vars);
196            parsedPoly = polyType.PolBigInt;
197            break;
198        case ModInt:
199            pfac = new GenPolynomialRing<ModInteger>(fac, nvars, tord, vars);
200            parsedPoly = polyType.PolModInt;
201            break;
202        case BigC:
203            pfac = new GenPolynomialRing<BigComplex>(fac, nvars, tord, vars);
204            parsedPoly = polyType.PolBigC;
205            break;
206        case BigQ:
207            pfac = new GenPolynomialRing<BigQuaternion>(fac, nvars, tord, vars);
208            parsedPoly = polyType.PolBigQ;
209            break;
210        case BigO:
211            pfac = new GenPolynomialRing<BigOctonion>(fac, nvars, tord, vars);
212            parsedPoly = polyType.PolBigO;
213            break;
214        case BigD:
215            pfac = new GenPolynomialRing<BigDecimal>(fac, nvars, tord, vars);
216            parsedPoly = polyType.PolBigD;
217            break;
218        case IntFunc:
219            pfac = new GenPolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars);
220            parsedPoly = polyType.PolIntFunc;
221            break;
222        default:
223            pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars);
224            parsedPoly = polyType.PolBigRat;
225        }
226    }
227
228
229    /**
230     * Initialize coefficient and solvable polynomial factories.
231     * @param rf ring factory.
232     * @param ct coefficient type.
233     */
234    @SuppressWarnings("unchecked")
235    public void initSolvableFactory(RingFactory rf, coeffType ct) {
236        fac = rf;
237        parsedCoeff = ct;
238
239        switch (ct) {
240        case BigRat:
241            spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars);
242            parsedPoly = polyType.PolBigRat;
243            break;
244        case BigInt:
245            spfac = new GenSolvablePolynomialRing<BigInteger>(fac, nvars, tord, vars);
246            parsedPoly = polyType.PolBigInt;
247            break;
248        case ModInt:
249            spfac = new GenSolvablePolynomialRing<ModInteger>(fac, nvars, tord, vars);
250            parsedPoly = polyType.PolModInt;
251            break;
252        case BigC:
253            spfac = new GenSolvablePolynomialRing<BigComplex>(fac, nvars, tord, vars);
254            parsedPoly = polyType.PolBigC;
255            break;
256        case BigQ:
257            spfac = new GenSolvablePolynomialRing<BigQuaternion>(fac, nvars, tord, vars);
258            parsedPoly = polyType.PolBigQ;
259            break;
260        case BigO:
261            spfac = new GenSolvablePolynomialRing<BigOctonion>(fac, nvars, tord, vars);
262            parsedPoly = polyType.PolBigO;
263            break;
264        case BigD:
265            spfac = new GenSolvablePolynomialRing<BigDecimal>(fac, nvars, tord, vars);
266            parsedPoly = polyType.PolBigD;
267            break;
268        case IntFunc:
269            spfac = new GenSolvablePolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars);
270            parsedPoly = polyType.PolIntFunc;
271            break;
272        default:
273            spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars);
274            parsedPoly = polyType.PolBigRat;
275        }
276    }
277
278
279    /**
280     * Parsing method for GenPolynomial. Syntax depends also on the syntax of
281     * the coefficients, as the respective parser is used. Basic term/monomial
282     * syntax:
283     * 
284     * <pre>
285     ... coefficient variable**exponent ... variable^exponent + ... - ....
286     * </pre>
287     * 
288     * Juxtaposition means multiplication <code>*</code>. Then terms/monomials
289     * can be added or subtracted <code>+, -</code> and grouped by parenthesis
290     * <code>()</code>. There are some heuristics to detect when a coefficient
291     * should be parsed. To force parsing of a coefficient enclose it in braces
292     * <code>{}</code>.
293     * @return the next polynomial.
294     * @throws IOException
295     */
296    @SuppressWarnings("unchecked")
297    public GenPolynomial nextPolynomial() throws IOException {
298        logger.debug("torder = {}", tord);
299        GenPolynomial a = pfac.getZERO();
300        GenPolynomial a1 = pfac.getONE();
301        ExpVector leer = pfac.evzero;
302
303        if (debug) {
304            logger.debug("a = {}", a);
305            logger.debug("a1 = {}", a1);
306        }
307        GenPolynomial b = a1;
308        GenPolynomial c;
309        int tt; //, oldtt;
310        //String rat = "";
311        char first;
312        RingElem r;
313        ExpVector e;
314        int ix;
315        long ie;
316        while (true) {
317            // next input. determine next action
318            tt = tok.nextToken();
319            //System.out.println("while tt = " + tok);
320            logger.debug("while tt = {}", tok);
321            if (tt == StreamTokenizer.TT_EOF)
322                break;
323            switch (tt) {
324            case ')':
325            case ',':
326                return a; // do not change or remove
327            case '-':
328                b = b.negate();
329            case '+':
330            case '*':
331                tt = tok.nextToken();
332                break;
333            default: // skip
334            }
335            // read coefficient, monic monomial and polynomial
336            if (tt == StreamTokenizer.TT_EOF)
337                break;
338            switch (tt) {
339            // case '_': removed 
340            case '}':
341                throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b);
342            case '{': // recursion
343                StringBuffer rf = new StringBuffer();
344                int level = 0;
345                do {
346                    tt = tok.nextToken();
347                    //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level);
348                    if (tt == StreamTokenizer.TT_EOF) {
349                        throw new InvalidExpressionException(
350                                        "mismatch of braces after " + a + ", error at " + b);
351                    }
352                    if (tt == '{') {
353                        level++;
354                    }
355                    if (tt == '}') {
356                        level--;
357                        if (level < 0) {
358                            continue; // skip last closing brace 
359                        }
360                    }
361                    if (tok.sval != null) {
362                        if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') {
363                            rf.append(" ");
364                        }
365                        rf.append(tok.sval); // " " + 
366                    } else {
367                        rf.append((char) tt);
368                    }
369                } while (level >= 0);
370                //System.out.println("coeff{} = " + rf.toString() );
371                try {
372                    r = (RingElem) fac.parse(rf.toString());
373                } catch (NumberFormatException re) {
374                    throw new InvalidExpressionException("not a number :" + rf + ": " + fac, re);
375                }
376                logger.debug("coeff {}", r);
377                ie = nextExponent();
378                logger.debug("ie {}", ie);
379                r = (RingElem) r.power(ie);
380                logger.debug("coeff^ie {}", r);
381                b = b.multiply(r, leer);
382
383                tt = tok.nextToken();
384                logger.debug("tt,digit = {}", tok);
385                //no break;
386                break;
387
388            //case '.': // eventually a float
389            //System.out.println("start . = " + reader);
390            //throw new InvalidExpressionException("float must start with a digit ");
391
392            case StreamTokenizer.TT_WORD:
393                //System.out.println("TT_WORD: " + tok.sval);
394                if (tok.sval == null || tok.sval.length() == 0)
395                    break;
396                // read coefficient
397                first = tok.sval.charAt(0);
398                if (digit(first) || first == '/' || first == '.' || first == '~') {
399                    //System.out.println("coeff 0 = " + tok.sval );
400                    StringBuffer df = new StringBuffer();
401                    df.append(tok.sval);
402                    if (tok.sval.length() > 1 && digit(tok.sval.charAt(1))) {
403                        //System.out.println("start / or . = " + tok.sval);
404                        if (first == '/') { // let x/2 be x 1/2
405                            df.insert(0, "1");
406                        }
407                        if (first == '.') { // let x.2 be x 0.2
408                            df.insert(0, "0");
409                        }
410                    }
411                    if (tok.sval.charAt(tok.sval.length() - 1) == 'i') { // complex number
412                        tt = tok.nextToken();
413                        logger.debug("tt,im = {}", tok);
414                        if (tok.sval != null || tt == '-') {
415                            if (tok.sval != null) {
416                                df.append(tok.sval);
417                            } else {
418                                df.append("-");
419                            }
420                            if (tt == '-') {
421                                tt = tok.nextToken(); // todo: decimal number
422                                if (tok.sval != null && digit(tok.sval.charAt(0))) {
423                                    df.append(tok.sval);
424
425                                } else {
426                                    tok.pushBack();
427                                }
428                            }
429                        } else {
430                            tok.pushBack();
431                        }
432                    }
433                    tt = tok.nextToken();
434                    if (tt == '.') { // decimal number, obsolete by word char?
435                        tt = tok.nextToken();
436                        logger.debug("tt,dot = {}", tok);
437                        if (tok.sval != null) {
438                            df.append(".");
439                            df.append(tok.sval);
440                        } else {
441                            tok.pushBack();
442                            tok.pushBack();
443                        }
444                    } else {
445                        tok.pushBack();
446                    }
447                    try {
448                        //System.out.println("df = " + df + ", fac = " + fac.getClass());
449                        r = (RingElem) fac.parse(df.toString());
450                        //System.out.println("r = " + r);
451                    } catch (NumberFormatException re) {
452                        //System.out.println("re = " + re);
453                        throw new InvalidExpressionException("not a number :" + df + ": " + fac, re);
454                    }
455                    logger.debug("coeff {}", r);
456                    //System.out.println("r = " + r.toScriptFactory());
457                    ie = nextExponent();
458                    logger.debug("ie {}", ie);
459                    // r = r^ie;
460                    r = (RingElem) r.power(ie);
461                    logger.debug("coeff^ie {}", r);
462                    b = b.multiply(r, leer);
463
464                    tt = tok.nextToken();
465                    logger.debug("tt,digit = {}", tok);
466                }
467                if (tt == StreamTokenizer.TT_EOF)
468                    break;
469                if (tok.sval == null)
470                    break;
471                // read monomial or recursion 
472                first = tok.sval.charAt(0);
473                if (letter(first)) {
474                    ix = leer.indexVar(tok.sval, vars); //indexVar( tok.sval );
475                    if (ix < 0) { // not found
476                        try {
477                            r = (RingElem) fac.parse(tok.sval);
478                        } catch (NumberFormatException re) {
479                            throw new InvalidExpressionException("recursively unknown variable " + tok.sval);
480                        }
481                        logger.info("coeff {}", r);
482                        //if (r.isONE() || r.isZERO()) {
483                        //logger.error("Unknown varibable {}", tok.sval);
484                        //break;
485                        //throw new InvalidExpressionException("recursively unknown variable " + tok.sval);
486                        //}
487                        ie = nextExponent();
488                        //  System.out.println("ie: " + ie);
489                        r = (RingElem) r.power(ie); //Power.<RingElem> positivePower(r, ie);
490                        b = b.multiply(r);
491                    } else { // found
492                        //  System.out.println("ix: " + ix);
493                        ie = nextExponent();
494                        //  System.out.println("ie: " + ie);
495                        e = ExpVector.create(vars.length, ix, ie);
496                        b = b.multiply(e);
497                    }
498                    tt = tok.nextToken();
499                    logger.debug("tt,letter = {}", tok);
500                }
501                break;
502
503            case '(':
504                c = nextPolynomial();
505                logger.debug("factor {}", c);
506                ie = nextExponent();
507                logger.debug("ie {}", ie);
508                c = (GenPolynomial) c.power(ie); //Power.<GenPolynomial> positivePower(c, ie);
509                logger.debug("factor^ie {}", c);
510                b = b.multiply(c);
511
512                tt = tok.nextToken();
513                logger.debug("tt,digit = {}", tok);
514                //no break;
515                break;
516
517            default: //skip 
518            }
519            if (tt == StreamTokenizer.TT_EOF)
520                break;
521            // complete polynomial
522            tok.pushBack();
523            switch (tt) {
524            case '-':
525            case '+':
526            case ')':
527            case ',':
528                logger.debug("b, = {}", b);
529                a = a.sum(b);
530                b = a1;
531                break;
532            case '*':
533                logger.debug("b, = {}", b);
534                //a = a.sum(b); 
535                //b = a1;
536                break;
537            case '\n':
538                tt = tok.nextToken();
539                logger.debug("tt,nl = {}", tt);
540                break;
541            default: // skip or finish ?
542                logger.debug("default: {}", tok);
543            }
544        }
545        logger.debug("b = {}", b);
546        a = a.sum(b);
547        logger.debug("a = {}", a);
548        // b = a1;
549        return a;
550    }
551
552
553    /**
554     * Parsing method for exponent (of variable). Syntax:
555     * 
556     * <pre>
557     * ^long | **long
558     * </pre>
559     * 
560     * @return the next exponent or 1.
561     * @throws IOException
562     */
563    public long nextExponent() throws IOException {
564        long e = 1;
565        char first;
566        int tt;
567        tt = tok.nextToken();
568        if (tt == '^') {
569            logger.debug("exponent ^");
570            tt = tok.nextToken();
571            if (tok.sval != null) {
572                first = tok.sval.charAt(0);
573                if (digit(first)) {
574                    e = Long.parseLong(tok.sval);
575                    return e;
576                }
577            }
578        }
579        if (tt == '*') {
580            tt = tok.nextToken();
581            if (tt == '*') {
582                logger.debug("exponent **");
583                tt = tok.nextToken();
584                if (tok.sval != null) {
585                    first = tok.sval.charAt(0);
586                    if (digit(first)) {
587                        e = Long.parseLong(tok.sval);
588                        return e;
589                    }
590                }
591            }
592            tok.pushBack();
593        }
594        tok.pushBack();
595        return e;
596    }
597
598
599    /**
600     * Parsing method for comments. Syntax:
601     * 
602     * <pre>
603     * (* comment *) | /_* comment *_/
604     * </pre>
605     * 
606     * without <code>_</code>. Unused, as it does not work with this pushBack().
607     */
608    public String nextComment() throws IOException {
609        // syntax: (* comment *) | /* comment */ 
610        StringBuffer c = new StringBuffer();
611        int tt;
612        logger.debug("comment: {}", tok);
613        tt = tok.nextToken();
614        logger.debug("comment: {}", tok);
615        if (tt == '(') {
616            tt = tok.nextToken();
617            logger.debug("comment: {}", tok);
618            if (tt == '*') {
619                logger.debug("comment: ");
620                while (true) {
621                    tt = tok.nextToken();
622                    if (tt == '*') {
623                        tt = tok.nextToken();
624                        if (tt == ')') {
625                            return c.toString();
626                        }
627                        tok.pushBack();
628                    }
629                    c.append(tok.sval);
630                }
631            }
632            tok.pushBack();
633            logger.debug("comment: {}", tok);
634        }
635        tok.pushBack();
636        logger.debug("comment: {}", tok);
637        return c.toString();
638    }
639
640
641    /**
642     * Parsing method for variable list. Syntax:
643     * 
644     * <pre>
645     * (a, b c, de)
646     * </pre>
647     * 
648     * gives <code>[ "a", "b", "c", "de" ]</code>
649     * @return the next variable list.
650     * @throws IOException
651     */
652    public String[] nextVariableList() throws IOException {
653        List<String> l = new ArrayList<String>();
654        int tt;
655        tt = tok.nextToken();
656        //System.out.println("vList tok = " + tok);
657        if (tt == '(' || tt == '{') {
658            logger.debug("variable list");
659            tt = tok.nextToken();
660            while (true) {
661                if (tt == StreamTokenizer.TT_EOF)
662                    break;
663                if (tt == ')' || tt == '}')
664                    break;
665                if (tt == StreamTokenizer.TT_WORD) {
666                    //System.out.println("TT_WORD: " + tok.sval);
667                    l.add(tok.sval);
668                }
669                tt = tok.nextToken();
670            }
671        } else {
672            tok.pushBack();
673        }
674        Object[] ol = l.toArray();
675        String[] v = new String[ol.length];
676        for (int i = 0; i < v.length; i++) {
677            v[i] = (String) ol[i];
678        }
679        return v;
680    }
681
682
683    /**
684     * Parsing method for coefficient ring. Syntax:
685     * 
686     * <pre>
687     * Rat | Q | Int | Z | Mod modul | Complex | C | D | Quat | AN[ (var) ( poly ) ] | AN[ modul (var) ( poly ) ] | IntFunc (var_list)
688     * </pre>
689     * 
690     * @return the next coefficient factory.
691     * @throws IOException
692     */
693    @SuppressWarnings({ "unchecked", "cast" })
694    public RingFactory nextCoefficientRing() throws IOException {
695        RingFactory coeff = null;
696        coeffType ct = null;
697        int tt;
698        tt = tok.nextToken();
699        if (tok.sval != null) {
700            if (tok.sval.equalsIgnoreCase("Q")) {
701                coeff = new BigRational(0);
702                ct = coeffType.BigRat;
703            } else if (tok.sval.equalsIgnoreCase("Rat")) {
704                coeff = new BigRational(0);
705                ct = coeffType.BigRat;
706            } else if (tok.sval.equalsIgnoreCase("D")) {
707                coeff = new BigDecimal(0);
708                ct = coeffType.BigD;
709            } else if (tok.sval.equalsIgnoreCase("Z")) {
710                coeff = new BigInteger(0);
711                ct = coeffType.BigInt;
712            } else if (tok.sval.equalsIgnoreCase("Int")) {
713                coeff = new BigInteger(0);
714                ct = coeffType.BigInt;
715            } else if (tok.sval.equalsIgnoreCase("C")) {
716                coeff = new BigComplex(0);
717                ct = coeffType.BigC;
718            } else if (tok.sval.equalsIgnoreCase("Complex")) {
719                coeff = new BigComplex(0);
720                ct = coeffType.BigC;
721            } else if (tok.sval.equalsIgnoreCase("Quat")) {
722                logger.warn("parse of quaternion coefficients may fail for negative components (use ~ for -)");
723                coeff = new BigQuaternionRing();
724                ct = coeffType.BigQ;
725            } else if (tok.sval.equalsIgnoreCase("Oct")) {
726                logger.warn("parse of octonion coefficients may fail for negative components (use ~ for -)");
727                coeff = new BigOctonion(new BigQuaternionRing());
728                ct = coeffType.BigO;
729            } else if (tok.sval.equalsIgnoreCase("Mod")) {
730                tt = tok.nextToken();
731                boolean openb = false;
732                if (tt == '[') { // optional
733                    openb = true;
734                    tt = tok.nextToken();
735                }
736                if (tok.sval != null && tok.sval.length() > 0) {
737                    if (digit(tok.sval.charAt(0))) {
738                        BigInteger mo = new BigInteger(tok.sval);
739                        BigInteger lm = new BigInteger(ModLongRing.MAX_LONG); //wrong: Long.MAX_VALUE);
740                        if (mo.compareTo(lm) < 0) {
741                            if (mo.compareTo(new BigInteger(ModIntRing.MAX_INT)) < 0) {
742                                coeff = new ModIntRing(mo.getVal());
743                            } else {
744                                coeff = new ModLongRing(mo.getVal());
745                            }
746                        } else {
747                            coeff = new ModIntegerRing(mo.getVal());
748                        }
749                        //System.out.println("coeff = " + coeff + " :: " + coeff.getClass());
750                        ct = coeffType.ModInt;
751                    } else {
752                        tok.pushBack();
753                    }
754                } else {
755                    tok.pushBack();
756                }
757                if (tt == ']' && openb) { // optional
758                    tt = tok.nextToken();
759                }
760            } else if (tok.sval.equalsIgnoreCase("RatFunc") || tok.sval.equalsIgnoreCase("ModFunc")) {
761                //logger.error("RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer.");
762                throw new InvalidExpressionException(
763                                "RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer.");
764            } else if (tok.sval.equalsIgnoreCase("IntFunc")) {
765                String[] rfv = nextVariableList();
766                //System.out.println("rfv = " + rfv.length + " " + rfv[0]);
767                int vr = rfv.length;
768                BigRational bi = new BigRational();
769                TermOrder to = new TermOrder(TermOrder.INVLEX);
770                GenPolynomialRing<BigRational> pcf = new GenPolynomialRing<BigRational>(bi, vr, to, rfv);
771                coeff = pcf;
772                ct = coeffType.IntFunc;
773            } else if (tok.sval.equalsIgnoreCase("AN")) {
774                tt = tok.nextToken();
775                if (tt == '[') {
776                    tt = tok.nextToken();
777                    RingFactory tcfac = new ModIntegerRing("19");
778                    if (tok.sval != null && tok.sval.length() > 0) {
779                        if (digit(tok.sval.charAt(0))) {
780                            tcfac = new ModIntegerRing(tok.sval);
781                        } else {
782                            tcfac = new BigRational();
783                            tok.pushBack();
784                        }
785                    } else {
786                        tcfac = new BigRational();
787                        tok.pushBack();
788                    }
789                    String[] anv = nextVariableList();
790                    //System.out.println("anv = " + anv.length + " " + anv[0]);
791                    int vs = anv.length;
792                    if (vs != 1) {
793                        throw new InvalidExpressionException(
794                                        "AlgebraicNumber only for univariate polynomials "
795                                                        + Arrays.toString(anv));
796                    }
797                    String[] ovars = vars;
798                    vars = anv;
799                    GenPolynomialRing tpfac = pfac;
800                    RingFactory tfac = fac;
801                    fac = tcfac;
802                    // pfac and fac used in nextPolynomial()
803                    if (tcfac instanceof ModIntegerRing) {
804                        pfac = new GenPolynomialRing<ModInteger>(tcfac, vs, new TermOrder(), anv);
805                    } else {
806                        pfac = new GenPolynomialRing<BigRational>(tcfac, vs, new TermOrder(), anv);
807                    }
808                    logger.debug("pfac = {}", pfac);
809                    tt = tok.nextToken();
810                    GenPolynomial mod;
811                    if (tt == '(') {
812                        mod = nextPolynomial();
813                        tt = tok.nextToken();
814                        if (tok.ttype != ')')
815                            tok.pushBack();
816                    } else {
817                        tok.pushBack();
818                        mod = nextPolynomial();
819                    }
820                    logger.debug("mod = {}", mod);
821                    pfac = tpfac;
822                    fac = tfac;
823                    vars = ovars;
824                    if (tcfac instanceof ModIntegerRing) {
825                        GenPolynomial<ModInteger> gfmod;
826                        gfmod = (GenPolynomial<ModInteger>) mod;
827                        coeff = new AlgebraicNumberRing<ModInteger>(gfmod);
828                        ct = coeffType.ANmod;
829                    } else {
830                        GenPolynomial<BigRational> anmod;
831                        anmod = (GenPolynomial<BigRational>) mod;
832                        coeff = new AlgebraicNumberRing<BigRational>(anmod);
833                        ct = coeffType.ANrat;
834                    }
835                    logger.debug("coeff = {}", coeff);
836                    tt = tok.nextToken();
837                    if (tt == ']') {
838                        //ok, no nextToken();
839                    } else {
840                        tok.pushBack();
841                    }
842                } else {
843                    tok.pushBack();
844                }
845            }
846        }
847        if (coeff == null) {
848            tok.pushBack();
849            coeff = new BigRational();
850            ct = coeffType.BigRat;
851        }
852        parsedCoeff = ct;
853        return coeff;
854    }
855
856
857    /**
858     * Parsing method for weight list. Syntax:
859     * 
860     * <pre>
861     * (w1, w2, w3, ..., wn)
862     * </pre>
863     * 
864     * @return the next weight list.
865     * @throws IOException
866     */
867    public long[] nextWeightList() throws IOException {
868        List<Long> l = new ArrayList<Long>();
869        long e;
870        char first;
871        int tt;
872        tt = tok.nextToken();
873        if (tt == '(') {
874            logger.debug("weight list");
875            tt = tok.nextToken();
876            while (true) {
877                if (tt == StreamTokenizer.TT_EOF)
878                    break;
879                if (tt == ')')
880                    break;
881                if (tok.sval != null) {
882                    first = tok.sval.charAt(0);
883                    if (digit(first)) {
884                        e = Long.parseLong(tok.sval);
885                        l.add(Long.valueOf(e));
886                        //System.out.println("w: " + e);
887                    }
888                }
889                tt = tok.nextToken(); // also comma
890            }
891        } else {
892            tok.pushBack();
893        }
894        Long[] ol = new Long[1];
895        ol = l.toArray(ol);
896        long[] w = new long[ol.length];
897        for (int i = 0; i < w.length; i++) {
898            w[i] = ol[ol.length - i - 1].longValue();
899        }
900        return w;
901    }
902
903
904    /**
905     * Parsing method for weight array. Syntax:
906     * 
907     * <pre>
908     * ( (w11, ...,w1n), ..., (wm1, ..., wmn) )
909     * </pre>
910     * 
911     * @return the next weight array.
912     * @throws IOException
913     */
914    public long[][] nextWeightArray() throws IOException {
915        List<long[]> l = new ArrayList<long[]>();
916        long[] e;
917        char first;
918        int tt;
919        tt = tok.nextToken();
920        if (tt == '(') {
921            logger.debug("weight array");
922            tt = tok.nextToken();
923            while (true) {
924                if (tt == StreamTokenizer.TT_EOF)
925                    break;
926                if (tt == ')')
927                    break;
928                if (tt == '(') {
929                    tok.pushBack();
930                    e = nextWeightList();
931                    l.add(e);
932                    //System.out.println("wa: " + e);
933                } else if (tok.sval != null) {
934                    first = tok.sval.charAt(0);
935                    if (digit(first)) {
936                        tok.pushBack();
937                        tok.pushBack();
938                        e = nextWeightList();
939                        l.add(e);
940                        break;
941                        //System.out.println("w: " + e);
942                    }
943                }
944                tt = tok.nextToken(); // also comma
945            }
946        } else {
947            tok.pushBack();
948        }
949        Object[] ol = l.toArray();
950        long[][] w = new long[ol.length][];
951        for (int i = 0; i < w.length; i++) {
952            w[i] = (long[]) ol[i];
953        }
954        return w;
955    }
956
957
958    /**
959     * Parsing method for split index. Syntax:
960     * 
961     * <pre>
962     * |i|
963     * </pre>
964     * 
965     * @return the next split index.
966     * @throws IOException
967     */
968    public int nextSplitIndex() throws IOException {
969        int e = -1; // =unknown
970        int e0 = -1; // =unknown
971        char first;
972        int tt;
973        tt = tok.nextToken();
974        if (tt == '|') {
975            logger.debug("split index");
976            tt = tok.nextToken();
977            if (tt == StreamTokenizer.TT_EOF) {
978                return e;
979            }
980            if (tok.sval != null) {
981                first = tok.sval.charAt(0);
982                if (digit(first)) {
983                    e = Integer.parseInt(tok.sval);
984                    //System.out.println("w: " + i);
985                }
986                tt = tok.nextToken();
987                if (tt != '|') {
988                    tok.pushBack();
989                }
990            }
991        } else if (tt == '[') {
992            logger.debug("split index");
993            tt = tok.nextToken();
994            if (tt == StreamTokenizer.TT_EOF) {
995                return e;
996            }
997            if (tok.sval != null) {
998                first = tok.sval.charAt(0);
999                if (digit(first)) {
1000                    e0 = Integer.parseInt(tok.sval);
1001                    //System.out.println("w: " + i);
1002                }
1003                tt = tok.nextToken();
1004                if (tt == ',') {
1005                    tt = tok.nextToken();
1006                    if (tt == StreamTokenizer.TT_EOF) {
1007                        return e0;
1008                    }
1009                    if (tok.sval != null) {
1010                        first = tok.sval.charAt(0);
1011                        if (digit(first)) {
1012                            e = Integer.parseInt(tok.sval);
1013                            //System.out.println("w: " + i);
1014                        }
1015                    }
1016                    if (tt != ']') {
1017                        tok.pushBack();
1018                    }
1019                }
1020            }
1021        } else {
1022            tok.pushBack();
1023        }
1024        return e;
1025    }
1026
1027
1028    /**
1029     * Parsing method for term order name. Syntax:
1030     * 
1031     * <pre>
1032     * L | IL | LEX | G | IG | GRLEX | W(weights) | '|'split index'|'
1033     * </pre>
1034     * 
1035     * @return the next term order.
1036     * @throws IOException
1037     */
1038    public TermOrder nextTermOrder() throws IOException {
1039        int evord = TermOrder.DEFAULT_EVORD;
1040        int tt;
1041        tt = tok.nextToken();
1042        if (tt == StreamTokenizer.TT_EOF) { /* nop */
1043        } else if (tt == StreamTokenizer.TT_WORD) {
1044            // System.out.println("TT_WORD: " + tok.sval);
1045            if (tok.sval != null) {
1046                if (tok.sval.equalsIgnoreCase("L")) {
1047                    evord = TermOrder.INVLEX;
1048                } else if (tok.sval.equalsIgnoreCase("IL")) {
1049                    evord = TermOrder.INVLEX;
1050                } else if (tok.sval.equalsIgnoreCase("INVLEX")) {
1051                    evord = TermOrder.INVLEX;
1052                } else if (tok.sval.equalsIgnoreCase("LEX")) {
1053                    evord = TermOrder.LEX;
1054                } else if (tok.sval.equalsIgnoreCase("G")) {
1055                    evord = TermOrder.IGRLEX;
1056                } else if (tok.sval.equalsIgnoreCase("IG")) {
1057                    evord = TermOrder.IGRLEX;
1058                } else if (tok.sval.equalsIgnoreCase("IGRLEX")) {
1059                    evord = TermOrder.IGRLEX;
1060                } else if (tok.sval.equalsIgnoreCase("GRLEX")) {
1061                    evord = TermOrder.GRLEX;
1062                } else if (tok.sval.equalsIgnoreCase("REVITDG")) {
1063                    evord = TermOrder.REVITDG;
1064                } else if (tok.sval.equalsIgnoreCase("REVILEX")) {
1065                    evord = TermOrder.REVILEX;
1066                } else if (tok.sval.equalsIgnoreCase("W")) {
1067                    long[][] w = nextWeightArray();
1068                    return new TermOrder(w);
1069                }
1070            }
1071        } else {
1072            tok.pushBack();
1073        }
1074        int s = nextSplitIndex();
1075        if (s <= 0) {
1076            return new TermOrder(evord);
1077        }
1078        return new TermOrder(evord, evord, nvars, s);
1079    }
1080
1081
1082    /**
1083     * Parsing method for polynomial list. Syntax:
1084     * 
1085     * <pre>
1086     * ( p1, p2, p3, ..., pn )
1087     * </pre>
1088     * 
1089     * @return the next polynomial list.
1090     * @throws IOException
1091     */
1092    public List<GenPolynomial> nextPolynomialList() throws IOException {
1093        GenPolynomial a;
1094        List<GenPolynomial> L = new ArrayList<GenPolynomial>();
1095        int tt;
1096        tt = tok.nextToken();
1097        if (tt == StreamTokenizer.TT_EOF)
1098            return L;
1099        if (tt != '(')
1100            return L;
1101        logger.debug("polynomial list");
1102        while (true) {
1103            tt = tok.nextToken();
1104            if (tok.ttype == ',')
1105                continue;
1106            if (tt == '(') {
1107                a = nextPolynomial();
1108                tt = tok.nextToken();
1109                if (tok.ttype != ')')
1110                    tok.pushBack();
1111            } else {
1112                tok.pushBack();
1113                a = nextPolynomial();
1114            }
1115            logger.info("next pol = {}", a);
1116            L.add(a);
1117            if (tok.ttype == StreamTokenizer.TT_EOF)
1118                break;
1119            if (tok.ttype == ')')
1120                break;
1121        }
1122        return L;
1123    }
1124
1125
1126    /**
1127     * Parsing method for submodule list. Syntax:
1128     * 
1129     * <pre>
1130     * ( ( p11, p12, p13, ..., p1n ), ..., ( pm1, pm2, pm3, ..., pmn ) )
1131     * </pre>
1132     * 
1133     * @return the next list of polynomial lists.
1134     * @throws IOException
1135     */
1136    public List<List<GenPolynomial>> nextSubModuleList() throws IOException {
1137        List<List<GenPolynomial>> L = new ArrayList<List<GenPolynomial>>();
1138        int tt;
1139        tt = tok.nextToken();
1140        if (tt == StreamTokenizer.TT_EOF)
1141            return L;
1142        if (tt != '(')
1143            return L;
1144        logger.debug("module list");
1145        List<GenPolynomial> v = null;
1146        while (true) {
1147            tt = tok.nextToken();
1148            if (tok.ttype == ',')
1149                continue;
1150            if (tok.ttype == ')')
1151                break;
1152            if (tok.ttype == StreamTokenizer.TT_EOF)
1153                break;
1154            if (tt == '(') {
1155                tok.pushBack();
1156                v = nextPolynomialList();
1157                logger.info("next vect = {}", v);
1158                L.add(v);
1159            }
1160        }
1161        return L;
1162    }
1163
1164
1165    /**
1166     * Parsing method for solvable polynomial relation table. Syntax:
1167     * 
1168     * <pre>
1169     * ( p_1, p_2, p_3, ..., p_{n+1}, p_{n+2}, p_{n+3} )
1170     * </pre>
1171     * 
1172     * semantics: <code>p_{n+1} * p_{n+2} = p_{n+3}</code>. The next relation
1173     * table is stored into the solvable polynomial factory.
1174     * @throws IOException
1175     */
1176    @SuppressWarnings("unchecked")
1177    public void nextRelationTable() throws IOException {
1178        if (spfac == null) {
1179            return;
1180        }
1181        RelationTable table = spfac.table;
1182        List<GenPolynomial> rels = null;
1183        GenPolynomial p;
1184        GenSolvablePolynomial sp;
1185        int tt;
1186        tt = tok.nextToken();
1187        logger.debug("start relation table: {}", tt);
1188        if (tok.sval != null) {
1189            if (tok.sval.equalsIgnoreCase("RelationTable")) {
1190                rels = nextPolynomialList();
1191            }
1192        }
1193        if (rels == null) {
1194            tok.pushBack();
1195            return;
1196        }
1197        for (Iterator<GenPolynomial> it = rels.iterator(); it.hasNext();) {
1198            p = it.next();
1199            ExpVector e = p.leadingExpVector();
1200            if (it.hasNext()) {
1201                p = it.next();
1202                ExpVector f = p.leadingExpVector();
1203                if (it.hasNext()) {
1204                    p = it.next();
1205                    sp = new GenSolvablePolynomial(spfac, p.val);
1206                    table.update(e, f, sp);
1207                }
1208            }
1209        }
1210        logger.info("table = {}", table);
1211        return;
1212    }
1213
1214
1215    /**
1216     * Parsing method for polynomial set. Syntax:
1217     * 
1218     * <pre>
1219     * coeffRing varList termOrderName polyList
1220     * </pre>
1221     * 
1222     * @return the next polynomial set.
1223     * @throws IOException
1224     */
1225    @SuppressWarnings("unchecked")
1226    public PolynomialList nextPolynomialSet() throws IOException {
1227        //String comments = "";
1228        //comments += nextComment();
1229        //if (debug) logger.debug("comment = {}", comments);
1230
1231        RingFactory coeff = nextCoefficientRing();
1232        logger.info("coeff = {}", coeff.getClass().getSimpleName());
1233
1234        vars = nextVariableList();
1235        logger.info("vars = {}", Arrays.toString(vars));
1236        if (vars != null) {
1237            nvars = vars.length;
1238        }
1239
1240        tord = nextTermOrder();
1241        logger.info("tord = {}", tord);
1242        // check more TOs
1243
1244        initFactory(coeff, parsedCoeff); // global: nvars, tord, vars
1245        List<GenPolynomial> s = null;
1246        s = nextPolynomialList();
1247        logger.info("s = {}", s);
1248        // comments += nextComment();
1249        return new PolynomialList(pfac, s);
1250    }
1251
1252
1253    /**
1254     * Parsing method for module set. Syntax:
1255     * 
1256     * <pre>
1257     * coeffRing varList termOrderName moduleList
1258     * </pre>
1259     * 
1260     * @return the next module set.
1261     * @throws IOException
1262     */
1263    @SuppressWarnings("unchecked")
1264    public ModuleList nextSubModuleSet() throws IOException {
1265        //String comments = "";
1266        //comments += nextComment();
1267        //if (debug) logger.debug("comment = {}", comments);
1268
1269        RingFactory coeff = nextCoefficientRing();
1270        logger.info("coeff = {}", coeff.getClass().getSimpleName());
1271
1272        vars = nextVariableList();
1273        logger.info("vars = {}", Arrays.toString(vars));
1274        if (vars != null) {
1275            nvars = vars.length;
1276        }
1277
1278        tord = nextTermOrder();
1279        logger.info("tord = {}", tord);
1280        // check more TOs
1281
1282        initFactory(coeff, parsedCoeff); // global: nvars, tord, vars
1283        List<List<GenPolynomial>> m = null;
1284        m = nextSubModuleList();
1285        logger.info("m = {}", m);
1286        // comments += nextComment();
1287
1288        return new ModuleList(pfac, m);
1289    }
1290
1291
1292    /**
1293     * Parsing method for solvable polynomial list. Syntax:
1294     * 
1295     * <pre>
1296     * ( p1, p2, p3, ..., pn )
1297     * </pre>
1298     * 
1299     * @return the next solvable polynomial list.
1300     * @throws IOException
1301     */
1302    @SuppressWarnings("unchecked")
1303    public List<GenSolvablePolynomial> nextSolvablePolynomialList() throws IOException {
1304        List<GenPolynomial> s = nextPolynomialList();
1305        logger.info("s = {}", s);
1306        // comments += nextComment();
1307
1308        GenPolynomial p;
1309        GenSolvablePolynomial ps;
1310        List<GenSolvablePolynomial> sp = new ArrayList<GenSolvablePolynomial>(s.size());
1311        for (Iterator<GenPolynomial> it = s.iterator(); it.hasNext();) {
1312            p = it.next();
1313            ps = new GenSolvablePolynomial(spfac, p.val);
1314            //System.out.println("ps = " + ps);
1315            sp.add(ps);
1316        }
1317        return sp;
1318    }
1319
1320
1321    /**
1322     * Parsing method for solvable polynomial. Syntax: same as for polynomial.
1323     * If the relation table is set-up, then multiplication will mean
1324     * solvable-multiplication.
1325     * @return the next polynomial.
1326     * @throws IOException
1327     */
1328    @SuppressWarnings("unchecked")
1329    public GenSolvablePolynomial nextSolvablePolynomial() throws IOException {
1330        GenPolynomial p = nextPolynomial();
1331        logger.info("nextSolvablePolynomial = {}", p);
1332        // comments += nextComment();
1333
1334        GenSolvablePolynomial ps = new GenSolvablePolynomial(spfac, p.val);
1335        //System.out.println("ps = " + ps);
1336        return ps;
1337    }
1338
1339
1340    /**
1341     * Parsing method for solvable polynomial set. Syntax:
1342     * 
1343     * <pre>
1344     * varList termOrderName relationTable polyList
1345     * </pre>
1346     * 
1347     * @return the next solvable polynomial set.
1348     * @throws IOException
1349     */
1350    @SuppressWarnings("unchecked")
1351    public PolynomialList nextSolvablePolynomialSet() throws IOException {
1352        //String comments = "";
1353        //comments += nextComment();
1354        //if (debug) logger.debug("comment = {}", comments);
1355
1356        RingFactory coeff = nextCoefficientRing();
1357        logger.info("coeff = {}", coeff.getClass().getSimpleName());
1358
1359        vars = nextVariableList();
1360        logger.info("vars = {}", Arrays.toString(vars));
1361        if (vars != null) {
1362            nvars = vars.length;
1363        }
1364
1365        tord = nextTermOrder();
1366        logger.info("tord = {}", tord);
1367        // check more TOs
1368
1369        initFactory(coeff, parsedCoeff); // must be because of symmetric read
1370        initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars
1371        //System.out.println("pfac = " + pfac);
1372        //System.out.println("spfac = " + spfac);
1373
1374        nextRelationTable();
1375        logger.info("table = {}", table);
1376
1377        List<GenSolvablePolynomial> s = null;
1378        s = nextSolvablePolynomialList();
1379        logger.info("s = {}", s);
1380        // comments += nextComment();
1381        return new PolynomialList(spfac, s); // Ordered ?
1382    }
1383
1384
1385    /**
1386     * Parsing method for solvable submodule list. Syntax:
1387     * 
1388     * <pre>
1389     * ( ( p11, p12, p13, ..., p1n ), ..., ( pm1, pm2, pm3, ..., pmn ) )
1390     * </pre>
1391     * 
1392     * @return the next list of solvable polynomial lists.
1393     * @throws IOException
1394     */
1395    public List<List<GenSolvablePolynomial>> nextSolvableSubModuleList() throws IOException {
1396        List<List<GenSolvablePolynomial>> L = new ArrayList<List<GenSolvablePolynomial>>();
1397        int tt;
1398        tt = tok.nextToken();
1399        if (tt == StreamTokenizer.TT_EOF)
1400            return L;
1401        if (tt != '(')
1402            return L;
1403        logger.debug("module list");
1404        List<GenSolvablePolynomial> v = null;
1405        while (true) {
1406            tt = tok.nextToken();
1407            if (tok.ttype == ',')
1408                continue;
1409            if (tok.ttype == ')')
1410                break;
1411            if (tok.ttype == StreamTokenizer.TT_EOF)
1412                break;
1413            if (tt == '(') {
1414                tok.pushBack();
1415                v = nextSolvablePolynomialList();
1416                logger.info("next vect = {}", v);
1417                L.add(v);
1418            }
1419        }
1420        return L;
1421    }
1422
1423
1424    /**
1425     * Parsing method for solvable module set. Syntax:
1426     * 
1427     * <pre>
1428     * varList termOrderName relationTable moduleList
1429     * </pre>
1430     * 
1431     * @return the next solvable module set.
1432     * @throws IOException
1433     */
1434    @SuppressWarnings("unchecked")
1435    public ModuleList nextSolvableSubModuleSet() throws IOException {
1436        //String comments = "";
1437        //comments += nextComment();
1438        //if (debug) logger.debug("comment = {}", comments);
1439
1440        RingFactory coeff = nextCoefficientRing();
1441        logger.info("coeff = {}", coeff.getClass().getSimpleName());
1442
1443        vars = nextVariableList();
1444        logger.info("vars = {}", Arrays.toString(vars));
1445        if (vars != null) {
1446            nvars = vars.length;
1447        }
1448
1449        tord = nextTermOrder();
1450        logger.info("tord = {}", tord);
1451        // check more TOs
1452
1453        initFactory(coeff, parsedCoeff); // must be because of symmetric read
1454        initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars
1455
1456        //System.out.println("spfac = " + spfac);
1457
1458        nextRelationTable();
1459        logger.info("table = {}", table);
1460
1461        List<List<GenSolvablePolynomial>> s = null;
1462        s = nextSolvableSubModuleList();
1463        logger.info("s = {}", s);
1464        // comments += nextComment();
1465
1466        return new OrderedModuleList(spfac, s); // Ordered
1467    }
1468
1469
1470    /**
1471     * Parsing method for word polynomial. Syntax: same as for polynomial.
1472     * Multiplication will be non commutative.
1473     * @return the next polynomial.
1474     * @throws IOException
1475     */
1476    @SuppressWarnings("unchecked")
1477    public GenWordPolynomial nextWordPolynomial() throws IOException {
1478        GenWordPolynomialRing wfac = new GenWordPolynomialRing(pfac);
1479        return nextWordPolynomial(wfac);
1480    }
1481
1482
1483    /**
1484     * Parsing method for word polynomial. Syntax: same as for polynomial.
1485     * Multiplication will be non commutative.
1486     * @param wfac word polynomial ring.
1487     * @return the next polynomial.
1488     * @throws IOException
1489     */
1490    @SuppressWarnings("unchecked")
1491    public GenWordPolynomial nextWordPolynomial(GenWordPolynomialRing wfac) throws IOException {
1492        //logger.info("wfac = {}", wfac);
1493        WordFactory wf = wfac.alphabet;
1494
1495        GenWordPolynomial a = wfac.getZERO();
1496        GenWordPolynomial a1 = wfac.getONE();
1497        Word leer = wfac.wone;
1498        RingFactory fac = wfac.coFac;
1499        if (debug) {
1500            logger.debug("a = {}", a);
1501            logger.debug("a1 = {}", a1);
1502        }
1503        GenWordPolynomial b = a1;
1504        GenWordPolynomial c;
1505        int tt;
1506        char first;
1507        RingElem r;
1508        Word e;
1509        //int ix;
1510        long ie;
1511        while (true) {
1512            // next input. determine next action
1513            tt = tok.nextToken();
1514            //System.out.println("while tt = " + tok);
1515            logger.debug("while tt = {}", tok);
1516            if (tt == StreamTokenizer.TT_EOF)
1517                break;
1518            switch (tt) {
1519            case ')':
1520            case ',':
1521                logger.info("nextWordPolynomial = {}", a);
1522                return a; // do not change or remove
1523            case '-':
1524                b = b.negate();
1525            case '+':
1526            case '*':
1527                tt = tok.nextToken();
1528                break;
1529            default: // skip
1530            }
1531            // read coefficient, monic monomial and polynomial
1532            if (tt == StreamTokenizer.TT_EOF)
1533                break;
1534            switch (tt) {
1535            // case '_': removed 
1536            case '}':
1537                throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b);
1538            case '{': // recursion
1539                StringBuffer rf = new StringBuffer();
1540                int level = 0;
1541                do {
1542                    tt = tok.nextToken();
1543                    //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level);
1544                    if (tt == StreamTokenizer.TT_EOF) {
1545                        throw new InvalidExpressionException(
1546                                        "mismatch of braces after " + a + ", error at " + b);
1547                    }
1548                    if (tt == '{') {
1549                        level++;
1550                    }
1551                    if (tt == '}') {
1552                        level--;
1553                        if (level < 0) {
1554                            continue; // skip last closing brace 
1555                        }
1556                    }
1557                    if (tok.sval != null) {
1558                        if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') {
1559                            rf.append(" ");
1560                        }
1561                        rf.append(tok.sval); // " " + 
1562                    } else {
1563                        rf.append((char) tt);
1564                    }
1565                } while (level >= 0);
1566                //System.out.println("coeff{} = " + rf.toString() );
1567                try {
1568                    r = (RingElem) fac.parse(rf.toString());
1569                } catch (NumberFormatException re) {
1570                    throw new InvalidExpressionException("not a number :" + rf + ": " + fac, re);
1571                }
1572                logger.debug("coeff {}", r);
1573                ie = nextExponent();
1574                logger.debug("ie {}", ie);
1575                r = (RingElem) r.power(ie);
1576                logger.debug("coeff^ie {}", r);
1577                b = b.multiply(r, leer);
1578
1579                tt = tok.nextToken();
1580                logger.debug("tt,digit = {}", tok);
1581                //no break;
1582                break;
1583
1584            //case '.': // eventually a float
1585            //System.out.println("start . = " + reader);
1586            //throw new InvalidExpressionException("float must start with a digit ");
1587
1588            case StreamTokenizer.TT_WORD:
1589                //System.out.println("TT_WORD: " + tok.sval);
1590                if (tok.sval == null || tok.sval.length() == 0)
1591                    break;
1592                // read coefficient
1593                first = tok.sval.charAt(0);
1594                if (digit(first) || first == '/' || first == '.' || first == '~') {
1595                    //System.out.println("coeff 0 = " + tok.sval );
1596                    StringBuffer df = new StringBuffer();
1597                    df.append(tok.sval);
1598                    if (tok.sval.length() > 1 && digit(tok.sval.charAt(1))) {
1599                        //System.out.println("start / or . = " + tok.sval);
1600                        if (first == '/') { // let x/2 be x 1/2
1601                            df.insert(0, "1");
1602                        }
1603                        if (first == '.') { // let x.2 be x 0.2
1604                            df.insert(0, "0");
1605                        }
1606                    }
1607                    if (tok.sval.charAt(tok.sval.length() - 1) == 'i') { // complex number
1608                        tt = tok.nextToken();
1609                        logger.debug("tt,im = {}", tok);
1610                        if (tok.sval != null || tt == '-') {
1611                            if (tok.sval != null) {
1612                                df.append(tok.sval);
1613                            } else {
1614                                df.append("-");
1615                            }
1616                            if (tt == '-') {
1617                                tt = tok.nextToken(); // todo: decimal number
1618                                if (tok.sval != null && digit(tok.sval.charAt(0))) {
1619                                    df.append(tok.sval);
1620
1621                                } else {
1622                                    tok.pushBack();
1623                                }
1624                            }
1625                        } else {
1626                            tok.pushBack();
1627                        }
1628                    }
1629                    tt = tok.nextToken();
1630                    if (tt == '.') { // decimal number, obsolete by word char?
1631                        tt = tok.nextToken();
1632                        logger.debug("tt,dot = {}", tok);
1633                        if (tok.sval != null) {
1634                            df.append(".");
1635                            df.append(tok.sval);
1636                        } else {
1637                            tok.pushBack();
1638                            tok.pushBack();
1639                        }
1640                    } else {
1641                        tok.pushBack();
1642                    }
1643                    try {
1644                        //System.out.println("df = " + df + ", fac = " + fac.getClass());
1645                        r = (RingElem) fac.parse(df.toString());
1646                        //System.out.println("r = " + r);
1647                    } catch (NumberFormatException re) {
1648                        //System.out.println("re = " + re);
1649                        throw new InvalidExpressionException("not a number :" + df + ": " + fac, re);
1650                    }
1651                    logger.debug("coeff {}", r);
1652                    //System.out.println("r = " + r.toScriptFactory());
1653                    ie = nextExponent();
1654                    logger.debug("ie {}", ie);
1655                    // r = r^ie;
1656                    r = (RingElem) r.power(ie); //Power.<RingElem> positivePower(r, ie);
1657                    logger.debug("coeff^ie {}", r);
1658                    b = b.multiply(r, leer);
1659
1660                    tt = tok.nextToken();
1661                    logger.debug("tt,digit = {}", tok);
1662                }
1663                if (tt == StreamTokenizer.TT_EOF)
1664                    break;
1665                if (tok.sval == null)
1666                    break;
1667                // read monomial or recursion 
1668                first = tok.sval.charAt(0);
1669                if (letter(first)) {
1670                    //ix = leer.indexVar(tok.sval, vars); 
1671                    try {
1672                        e = wf.parse(tok.sval);
1673                    } catch (IllegalArgumentException ee) {
1674                        e = null;
1675                    }
1676                    logger.info("monom {}", e);
1677                    if (e == null) { // not found, look for coeff var
1678                        try {
1679                            r = (RingElem) fac.parse(tok.sval);
1680                        } catch (NumberFormatException re) {
1681                            throw new InvalidExpressionException("recursively unknown variable " + tok.sval);
1682                        }
1683                        ie = nextExponent();
1684                        //  System.out.println("ie: " + ie);
1685                        r = (RingElem) r.power(ie);
1686                        //  System.out.println("re:  " + r);
1687                        b = b.multiply(r, leer);
1688                    } else { // found
1689                        ie = nextExponent();
1690                        //  System.out.println("ie: " + ie);
1691                        e = e.power(ie);
1692                        //  System.out.println("e:  " + e);
1693                        b = b.multiply(e);
1694                    }
1695                    tt = tok.nextToken();
1696                    logger.debug("tt,letter = {}", tok);
1697                }
1698                break;
1699
1700            case '(':
1701                c = nextWordPolynomial(wfac);
1702                logger.debug("factor {}", c);
1703                ie = nextExponent();
1704                logger.debug("ie {}", ie);
1705                c = (GenWordPolynomial) c.power(ie); //Power.<GenPolynomial> positivePower(c, ie);
1706                logger.debug("factor^ie {}", c);
1707                b = b.multiply(c);
1708
1709                tt = tok.nextToken();
1710                logger.debug("tt,digit = {}", tok);
1711                //no break;
1712                break;
1713
1714            default: //skip 
1715            }
1716            if (tt == StreamTokenizer.TT_EOF)
1717                break;
1718            // complete polynomial
1719            tok.pushBack();
1720            switch (tt) {
1721            case '-':
1722            case '+':
1723            case ')':
1724            case ',':
1725                logger.debug("b, = {}", b);
1726                a = a.sum(b);
1727                b = a1;
1728                break;
1729            case '*':
1730                logger.debug("b, = {}", b);
1731                //a = a.sum(b); 
1732                //b = a1;
1733                break;
1734            case '\n':
1735                tt = tok.nextToken();
1736                logger.debug("tt,nl = {}", tt);
1737                break;
1738            default: // skip or finish ?
1739                logger.debug("default: {}", tok);
1740            }
1741        }
1742        logger.debug("b = {}", b);
1743        a = a.sum(b);
1744        logger.info("nextWordPolynomial = {}", a);
1745        // b = a1;
1746        return a;
1747    }
1748
1749
1750    /**
1751     * Parsing method for word polynomial list. Syntax:
1752     *
1753     * <pre>
1754     * ( p1, p2, p3, ..., pn )
1755     * </pre>
1756     *
1757     * @return the next word polynomial list.
1758     * @throws IOException
1759     */
1760    @SuppressWarnings("unchecked")
1761    public List<GenWordPolynomial> nextWordPolynomialList() throws IOException {
1762        GenWordPolynomialRing wfac = new GenWordPolynomialRing(pfac);
1763        return nextWordPolynomialList(wfac);
1764    }
1765
1766
1767    /**
1768     * Parsing method for word polynomial list. Syntax:
1769     *
1770     * <pre>
1771     * ( p1, p2, p3, ..., pn )
1772     * </pre>
1773     *
1774     * @param wfac word polynomial ring.
1775     * @return the next word polynomial list.
1776     * @throws IOException
1777     */
1778    public List<GenWordPolynomial> nextWordPolynomialList(GenWordPolynomialRing wfac) throws IOException {
1779        GenWordPolynomial a;
1780        List<GenWordPolynomial> L = new ArrayList<GenWordPolynomial>();
1781        int tt;
1782        tt = tok.nextToken();
1783        if (tt == StreamTokenizer.TT_EOF)
1784            return L;
1785        if (tt != '(')
1786            return L;
1787        logger.debug("word polynomial list");
1788        while (true) {
1789            tt = tok.nextToken();
1790            if (tok.ttype == ',')
1791                continue;
1792            if (tt == '(') {
1793                a = nextWordPolynomial(wfac);
1794                tt = tok.nextToken();
1795                if (tok.ttype != ')')
1796                    tok.pushBack();
1797            } else {
1798                tok.pushBack();
1799                a = nextWordPolynomial(wfac);
1800            }
1801            logger.info("next pol = {}", a);
1802            L.add(a);
1803            if (tok.ttype == StreamTokenizer.TT_EOF)
1804                break;
1805            if (tok.ttype == ')')
1806                break;
1807        }
1808        return L;
1809    }
1810
1811
1812    // must also allow +/- // does not work with tokenizer
1813    //private static boolean number(char x) {
1814    //    return digit(x) || x == '-' || x == '+';
1815    //}
1816
1817
1818    static boolean digit(char x) {
1819        return '0' <= x && x <= '9';
1820    }
1821
1822
1823    static boolean letter(char x) {
1824        return ('a' <= x && x <= 'z') || ('A' <= x && x <= 'Z');
1825    }
1826
1827
1828    // unused
1829    public void nextComma() throws IOException {
1830        int tt;
1831        if (tok.ttype == ',') {
1832            tt = tok.nextToken();
1833            logger.debug("after comma: {}", tt);
1834        }
1835    }
1836
1837
1838    /**
1839     * Parse variable list from String.
1840     * @param s String. Syntax:
1841     * 
1842     *            <pre>
1843     * (n1,...,nk)
1844     *            </pre>
1845     * 
1846     *            or
1847     * 
1848     *            <pre>
1849     * (n1 ... nk)
1850     *            </pre>
1851     * 
1852     *            parenthesis are optional.
1853     * @return array of variable names found in s.
1854     */
1855    public static String[] variableList(String s) {
1856        String[] vl = null;
1857        if (s == null) {
1858            return vl;
1859        }
1860        String st = s.trim();
1861        if (st.length() == 0) {
1862            return new String[0];
1863        }
1864        if (st.charAt(0) == '(') {
1865            st = st.substring(1);
1866        }
1867        if (st.charAt(st.length() - 1) == ')') {
1868            st = st.substring(0, st.length() - 1);
1869        }
1870        st = st.replaceAll(",", " ");
1871        List<String> sl = new ArrayList<String>();
1872        Scanner sc = new Scanner(st);
1873        while (sc.hasNext()) {
1874            String sn = sc.next();
1875            sl.add(sn);
1876        }
1877        sc.close();
1878        vl = new String[sl.size()];
1879        int i = 0;
1880        for (String si : sl) {
1881            vl[i] = si;
1882            i++;
1883        }
1884        return vl;
1885    }
1886
1887
1888    /**
1889     * Extract variable list from expression.
1890     * @param s String. Syntax: any polynomial expression.
1891     * @return array of variable names found in s.
1892     */
1893    public static String[] expressionVariables(String s) {
1894        String[] vl = null;
1895        if (s == null) {
1896            return vl;
1897        }
1898        String st = s.trim();
1899        if (st.length() == 0) {
1900            return new String[0];
1901        }
1902        st = st.replaceAll(",", " ");
1903        st = st.replaceAll("\\+", " ");
1904        st = st.replaceAll("-", " ");
1905        st = st.replaceAll("\\*", " ");
1906        st = st.replaceAll("/", " ");
1907        st = st.replaceAll("\\(", " ");
1908        st = st.replaceAll("\\)", " ");
1909        st = st.replaceAll("\\{", " ");
1910        st = st.replaceAll("\\}", " ");
1911        st = st.replaceAll("\\[", " ");
1912        st = st.replaceAll("\\]", " ");
1913        st = st.replaceAll("\\^", " ");
1914        //System.out.println("st = " + st);
1915
1916        Set<String> sl = new TreeSet<String>();
1917        Scanner sc = new Scanner(st);
1918        while (sc.hasNext()) {
1919            String sn = sc.next();
1920            if (sn == null || sn.length() == 0) {
1921                continue;
1922            }
1923            //System.out.println("sn = " + sn);
1924            int i = 0;
1925            while (digit(sn.charAt(i)) && i < sn.length() - 1) {
1926                i++;
1927            }
1928            //System.out.println("sn = " + sn + ", i = " + i);
1929            if (i > 0) {
1930                sn = sn.substring(i, sn.length());
1931            }
1932            //System.out.println("sn = " + sn);
1933            if (sn.length() == 0) {
1934                continue;
1935            }
1936            if (!letter(sn.charAt(0))) {
1937                continue;
1938            }
1939            //System.out.println("sn = " + sn);
1940            sl.add(sn);
1941        }
1942        sc.close();
1943        vl = new String[sl.size()];
1944        int i = 0;
1945        for (String si : sl) {
1946            vl[i] = si;
1947            i++;
1948        }
1949        return vl;
1950    }
1951
1952}