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