001/*
002 * $Id$
003 */
004
005package edu.jas.application;
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;
019
020import org.apache.logging.log4j.Logger;
021import org.apache.logging.log4j.LogManager; 
022
023import edu.jas.arith.BigComplex;
024import edu.jas.arith.BigDecimal;
025import edu.jas.arith.BigInteger;
026import edu.jas.arith.BigQuaternion;
027import edu.jas.arith.BigQuaternionRing;
028import edu.jas.arith.BigRational;
029import edu.jas.arith.ModInteger;
030import edu.jas.arith.ModIntegerRing;
031import edu.jas.arith.ModIntRing;
032import edu.jas.arith.ModLongRing;
033import edu.jas.poly.AlgebraicNumberRing;
034import edu.jas.poly.ExpVector;
035import edu.jas.poly.GenPolynomial;
036import edu.jas.poly.GenPolynomialRing;
037import edu.jas.poly.GenPolynomialTokenizer;
038import edu.jas.poly.GenSolvablePolynomial;
039import edu.jas.poly.GenSolvablePolynomialRing;
040import edu.jas.poly.InvalidExpressionException;
041import edu.jas.poly.RelationTable;
042import edu.jas.poly.TermOrder;
043import edu.jas.poly.ModuleList;
044import edu.jas.poly.PolynomialList;
045import edu.jas.structure.RingFactory;
046import edu.jas.ufd.Quotient;
047import edu.jas.ufd.QuotientRing;
048
049
050/**
051 * RingFactory Tokenizer. Used to read ring factories from input streams. It can
052 * also read QuotientRing factory.
053 * @see edu.jas.poly.GenPolynomialTokenizer
054 * @author Heinz Kredel
055 */
056public class RingFactoryTokenizer {
057
058
059    private static final Logger logger = LogManager.getLogger(RingFactoryTokenizer.class);
060
061
062    private static final boolean debug = logger.isDebugEnabled();
063
064
065    private String[] vars;
066
067
068    private int nvars = 1;
069
070
071    private TermOrder tord;
072
073
074    private RelationTable table;
075
076
077    private final StreamTokenizer tok;
078
079
080    private final Reader reader;
081
082
083    private RingFactory fac;
084
085
086    private static enum coeffType {
087        BigRat, BigInt, ModInt, BigC, BigQ, BigD, ANrat, ANmod, RatFunc, ModFunc, IntFunc
088    };
089
090
091    private coeffType parsedCoeff = coeffType.BigRat;
092
093
094    private GenPolynomialRing pfac;
095
096
097    private static enum polyType {
098        PolBigRat, PolBigInt, PolModInt, PolBigC, PolBigD, PolBigQ, PolANrat, PolANmod, PolRatFunc, PolModFunc, PolIntFunc
099    };
100
101
102    @SuppressWarnings("unused")
103    private polyType parsedPoly = polyType.PolBigRat;
104
105
106    private GenSolvablePolynomialRing spfac;
107
108
109    /**
110     * No-args constructor reads from System.in.
111     */
112    public RingFactoryTokenizer() {
113        this(new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF8"))));
114    }
115
116
117    /**
118     * Constructor with Ring and Reader.
119     * @param rf ring factory.
120     * @param r reader stream.
121     */
122    public RingFactoryTokenizer(GenPolynomialRing rf, Reader r) {
123        this(r);
124        if (rf == null) {
125            return;
126        }
127        if (rf instanceof GenSolvablePolynomialRing) {
128            pfac = rf;
129            spfac = (GenSolvablePolynomialRing) rf;
130        } else {
131            pfac = rf;
132            spfac = null;
133        }
134        fac = rf.coFac;
135        vars = rf.getVars();
136        if (vars != null) {
137            nvars = vars.length;
138        }
139        tord = rf.tord;
140        // relation table
141        if (spfac != null) {
142            table = spfac.table;
143        } else {
144            table = null;
145        }
146    }
147
148
149    /**
150     * Constructor with Reader.
151     * @param r reader stream.
152     */
153    @SuppressWarnings("unchecked")
154    public RingFactoryTokenizer(Reader r) {
155        vars = null;
156        tord = new TermOrder();
157        nvars = 1;
158        fac = new BigRational(1);
159
160        pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars);
161        spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars);
162
163        reader = r;
164        tok = new StreamTokenizer(reader);
165        tok.resetSyntax();
166        // tok.eolIsSignificant(true); no more
167        tok.eolIsSignificant(false);
168        tok.wordChars('0', '9');
169        tok.wordChars('a', 'z');
170        tok.wordChars('A', 'Z');
171        tok.wordChars('_', '_'); // for subscripts x_i
172        tok.wordChars('/', '/'); // wg. rational numbers
173        tok.wordChars('.', '.'); // wg. floats
174        tok.wordChars('~', '~'); // wg. quaternions // unused in this class
175        tok.wordChars(128 + 32, 255);
176        tok.whitespaceChars(0, ' ');
177        tok.commentChar('#');
178        tok.quoteChar('"');
179        tok.quoteChar('\'');
180        //tok.slashStarComments(true); does not work
181
182    }
183
184
185    /**
186     * Initialize coefficient and polynomial factories.
187     * @param rf ring factory.
188     * @param ct coefficient type.
189     */
190    @SuppressWarnings("unchecked")
191    public void initFactory(RingFactory rf, coeffType ct) {
192        fac = rf;
193        parsedCoeff = ct;
194
195        switch (ct) {
196        case BigRat:
197            pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars);
198            parsedPoly = polyType.PolBigRat;
199            break;
200        case BigInt:
201            pfac = new GenPolynomialRing<BigInteger>(fac, nvars, tord, vars);
202            parsedPoly = polyType.PolBigInt;
203            break;
204        case ModInt:
205            pfac = new GenPolynomialRing<ModInteger>(fac, nvars, tord, vars);
206            parsedPoly = polyType.PolModInt;
207            break;
208        case BigC:
209            pfac = new GenPolynomialRing<BigComplex>(fac, nvars, tord, vars);
210            parsedPoly = polyType.PolBigC;
211            break;
212        case BigQ:
213            pfac = new GenPolynomialRing<BigQuaternion>(fac, nvars, tord, vars);
214            parsedPoly = polyType.PolBigQ;
215            break;
216        case BigD:
217            pfac = new GenPolynomialRing<BigDecimal>(fac, nvars, tord, vars);
218            parsedPoly = polyType.PolBigD;
219            break;
220        case RatFunc:
221            pfac = new GenPolynomialRing<Quotient<BigInteger>>(fac, nvars, tord, vars);
222            parsedPoly = polyType.PolRatFunc;
223            break;
224        case ModFunc:
225            pfac = new GenPolynomialRing<Quotient<ModInteger>>(fac, nvars, tord, vars);
226            parsedPoly = polyType.PolModFunc;
227            break;
228        case IntFunc:
229            pfac = new GenPolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars);
230            parsedPoly = polyType.PolIntFunc;
231            break;
232        default:
233            pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars);
234            parsedPoly = polyType.PolBigRat;
235        }
236    }
237
238
239    /**
240     * Initialize coefficient and solvable polynomial factories.
241     * @param rf ring factory.
242     * @param ct coefficient type.
243     */
244    @SuppressWarnings("unchecked")
245    public void initSolvableFactory(RingFactory rf, coeffType ct) {
246        fac = rf;
247        parsedCoeff = ct;
248
249        switch (ct) {
250        case BigRat:
251            spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars);
252            parsedPoly = polyType.PolBigRat;
253            break;
254        case BigInt:
255            spfac = new GenSolvablePolynomialRing<BigInteger>(fac, nvars, tord, vars);
256            parsedPoly = polyType.PolBigInt;
257            break;
258        case ModInt:
259            spfac = new GenSolvablePolynomialRing<ModInteger>(fac, nvars, tord, vars);
260            parsedPoly = polyType.PolModInt;
261            break;
262        case BigC:
263            spfac = new GenSolvablePolynomialRing<BigComplex>(fac, nvars, tord, vars);
264            parsedPoly = polyType.PolBigC;
265            break;
266        case BigQ:
267            spfac = new GenSolvablePolynomialRing<BigQuaternion>(fac, nvars, tord, vars);
268            parsedPoly = polyType.PolBigQ;
269            break;
270        case BigD:
271            spfac = new GenSolvablePolynomialRing<BigDecimal>(fac, nvars, tord, vars);
272            parsedPoly = polyType.PolBigD;
273            break;
274        case RatFunc:
275            spfac = new GenSolvablePolynomialRing<Quotient<BigInteger>>(fac, nvars, tord, vars);
276            parsedPoly = polyType.PolRatFunc;
277            break;
278        case ModFunc:
279            spfac = new GenSolvablePolynomialRing<Quotient<ModInteger>>(fac, nvars, tord, vars);
280            parsedPoly = polyType.PolModFunc;
281            break;
282        case IntFunc:
283            spfac = new GenSolvablePolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars);
284            parsedPoly = polyType.PolIntFunc;
285            break;
286        default:
287            spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars);
288            parsedPoly = polyType.PolBigRat;
289        }
290    }
291
292
293    /**
294     * Parsing method for variable list. Syntax:
295     * 
296     * <pre>
297     * (a, b c, de)
298     * </pre>
299     * 
300     * gives <code>[ "a", "b", "c", "de" ]</code>
301     * @return the next variable list.
302     * @throws IOException
303     */
304    public String[] nextVariableList() throws IOException {
305        List<String> l = new ArrayList<String>();
306        int tt;
307        tt = tok.nextToken();
308        //System.out.println("vList tok = " + tok);
309        if (tt == '(' || tt == '{') {
310            logger.debug("variable list");
311            tt = tok.nextToken();
312            while (true) {
313                if (tt == StreamTokenizer.TT_EOF)
314                    break;
315                if (tt == ')' || tt == '}')
316                    break;
317                if (tt == StreamTokenizer.TT_WORD) {
318                    //System.out.println("TT_WORD: " + tok.sval);
319                    l.add(tok.sval);
320                }
321                tt = tok.nextToken();
322            }
323        } else {
324            tok.pushBack();
325        }
326        Object[] ol = l.toArray();
327        String[] v = new String[ol.length];
328        for (int i = 0; i < v.length; i++) {
329            v[i] = (String) ol[i];
330        }
331        return v;
332    }
333
334
335    /**
336     * Parsing method for coefficient ring. Syntax:
337     * 
338     * <pre>
339     * Rat | Q | Int | Z | Mod modul | Complex | C | D | Quat |
340    AN[ (var) ( poly ) | AN[ modul (var) ( poly ) ] | 
341    RatFunc (var_list) | ModFunc modul (var_list) | IntFunc (var_list)
342     * </pre>
343     * 
344     * @return the next coefficient factory.
345     * @throws IOException
346     */
347    @SuppressWarnings({ "unchecked", "cast" })
348    public RingFactory nextCoefficientRing() throws IOException {
349        RingFactory coeff = null;
350        coeffType ct = null;
351        int tt;
352        tt = tok.nextToken();
353        if (tok.sval != null) {
354            if (tok.sval.equalsIgnoreCase("Q")) {
355                coeff = new BigRational(0);
356                ct = coeffType.BigRat;
357            } else if (tok.sval.equalsIgnoreCase("Rat")) {
358                coeff = new BigRational(0);
359                ct = coeffType.BigRat;
360            } else if (tok.sval.equalsIgnoreCase("D")) {
361                coeff = new BigDecimal(0);
362                ct = coeffType.BigD;
363            } else if (tok.sval.equalsIgnoreCase("Z")) {
364                coeff = new BigInteger(0);
365                ct = coeffType.BigInt;
366            } else if (tok.sval.equalsIgnoreCase("Int")) {
367                coeff = new BigInteger(0);
368                ct = coeffType.BigInt;
369            } else if (tok.sval.equalsIgnoreCase("C")) {
370                coeff = new BigComplex(0);
371                ct = coeffType.BigC;
372            } else if (tok.sval.equalsIgnoreCase("Complex")) {
373                coeff = new BigComplex(0);
374                ct = coeffType.BigC;
375            } else if (tok.sval.equalsIgnoreCase("Quat")) {
376                logger.warn("parse of quaternion coefficients may fail for negative components (use ~ for -)");
377                coeff = new BigQuaternionRing();
378                ct = coeffType.BigQ;
379            } else if (tok.sval.equalsIgnoreCase("Mod")) {
380                tt = tok.nextToken();
381                boolean openb = false;
382                if (tt == '[') { // optional
383                    openb = true;
384                    tt = tok.nextToken();
385                }
386                if (tok.sval != null && tok.sval.length() > 0) {
387                    if (digit(tok.sval.charAt(0))) {
388                        BigInteger mo = new BigInteger(tok.sval);
389                        BigInteger lm = new BigInteger(ModLongRing.MAX_LONG); //wrong: Long.MAX_VALUE);
390                        if (mo.compareTo(lm) < 0) {
391                            if (mo.compareTo(new BigInteger(ModIntRing.MAX_INT)) < 0) {
392                                coeff = new ModIntRing(mo.getVal());
393                            } else {
394                                coeff = new ModLongRing(mo.getVal());
395                            }
396                        } else {
397                            coeff = new ModIntegerRing(mo.getVal());
398                        }
399                        //System.out.println("coeff = " + coeff + " :: " + coeff.getClass());
400                        ct = coeffType.ModInt;
401                    } else {
402                        tok.pushBack();
403                    }
404                } else {
405                    tok.pushBack();
406                }
407                if (tt == ']' && openb) { // optional
408                    tt = tok.nextToken();
409                }
410            } else if (tok.sval.equalsIgnoreCase("RatFunc")) {
411                String[] rfv = nextVariableList();
412                //System.out.println("rfv = " + rfv.length + " " + rfv[0]);
413                int vr = rfv.length;
414                BigInteger bi = new BigInteger();
415                TermOrder to = new TermOrder(TermOrder.INVLEX);
416                GenPolynomialRing<BigInteger> pcf = new GenPolynomialRing<BigInteger>(bi, vr, to, rfv);
417                coeff = new QuotientRing(pcf);
418                ct = coeffType.RatFunc;
419            } else if (tok.sval.equalsIgnoreCase("ModFunc")) {
420                tt = tok.nextToken();
421                RingFactory mi = new ModIntegerRing("19");
422                if (tok.sval != null && tok.sval.length() > 0) {
423                    if (digit(tok.sval.charAt(0))) {
424                        mi = new ModIntegerRing(tok.sval);
425                    } else {
426                        tok.pushBack();
427                    }
428                } else {
429                    tok.pushBack();
430                }
431                String[] rfv = nextVariableList();
432                //System.out.println("rfv = " + rfv.length + " " + rfv[0]);
433                int vr = rfv.length;
434                TermOrder to = new TermOrder(TermOrder.INVLEX);
435                GenPolynomialRing<ModInteger> pcf = new GenPolynomialRing<ModInteger>(mi, vr, to, rfv);
436                coeff = new QuotientRing(pcf);
437                ct = coeffType.ModFunc;
438            } else if (tok.sval.equalsIgnoreCase("IntFunc")) {
439                String[] rfv = nextVariableList();
440                //System.out.println("rfv = " + rfv.length + " " + rfv[0]);
441                int vr = rfv.length;
442                BigRational bi = new BigRational();
443                TermOrder to = new TermOrder(TermOrder.INVLEX);
444                GenPolynomialRing<BigRational> pcf = new GenPolynomialRing<BigRational>(bi, vr, to, rfv);
445                coeff = pcf;
446                ct = coeffType.IntFunc;
447            } else if (tok.sval.equalsIgnoreCase("AN")) {
448                tt = tok.nextToken();
449                if (tt == '[') {
450                    tt = tok.nextToken();
451                    RingFactory tcfac = new ModIntegerRing("19");
452                    if (tok.sval != null && tok.sval.length() > 0) {
453                        if (digit(tok.sval.charAt(0))) {
454                            tcfac = new ModIntegerRing(tok.sval);
455                        } else {
456                            tcfac = new BigRational();
457                            tok.pushBack();
458                        }
459                    } else {
460                        tcfac = new BigRational();
461                        tok.pushBack();
462                    }
463                    String[] anv = nextVariableList();
464                    //System.out.println("anv = " + anv.length + " " + anv[0]);
465                    int vs = anv.length;
466                    if (vs != 1) {
467                        throw new InvalidExpressionException(
468                                        "AlgebraicNumber only for univariate polynomials "
469                                                        + Arrays.toString(anv));
470                    }
471                    String[] ovars = vars;
472                    vars = anv;
473                    GenPolynomialRing tpfac = pfac;
474                    RingFactory tfac = fac;
475                    fac = tcfac;
476                    // pfac and fac used in nextPolynomial()
477                    if (tcfac instanceof ModIntegerRing) {
478                        pfac = new GenPolynomialRing<ModInteger>(tcfac, vs, new TermOrder(), anv);
479                    } else {
480                        pfac = new GenPolynomialRing<BigRational>(tcfac, vs, new TermOrder(), anv);
481                    }
482                    logger.debug("pfac = {}", pfac);
483                    GenPolynomialTokenizer ptok = new GenPolynomialTokenizer(pfac, reader);
484                    GenPolynomial mod = ptok.nextPolynomial();
485                    ptok = null;
486                    logger.debug("mod = {}", mod);
487                    pfac = tpfac;
488                    fac = tfac;
489                    vars = ovars;
490                    if (tcfac instanceof ModIntegerRing) {
491                        GenPolynomial<ModInteger> gfmod;
492                        gfmod = (GenPolynomial<ModInteger>) mod;
493                        coeff = new AlgebraicNumberRing<ModInteger>(gfmod);
494                        ct = coeffType.ANmod;
495                    } else {
496                        GenPolynomial<BigRational> anmod;
497                        anmod = (GenPolynomial<BigRational>) mod;
498                        coeff = new AlgebraicNumberRing<BigRational>(anmod);
499                        ct = coeffType.ANrat;
500                    }
501                    logger.debug("coeff = {}", coeff);
502                    tt = tok.nextToken();
503                    if (tt == ']') {
504                        //ok, no nextToken();
505                    } else {
506                        tok.pushBack();
507                    }
508                } else {
509                    tok.pushBack();
510                }
511            }
512        }
513        if (coeff == null) {
514            tok.pushBack();
515            coeff = new BigRational();
516            ct = coeffType.BigRat;
517        }
518        parsedCoeff = ct;
519        return coeff;
520    }
521
522
523    /**
524     * Parsing method for weight list. Syntax:
525     * 
526     * <pre>
527     * (w1, w2, w3, ..., wn)
528     * </pre>
529     * 
530     * @return the next weight list.
531     * @throws IOException
532     */
533    public long[] nextWeightList() throws IOException {
534        List<Long> l = new ArrayList<Long>();
535        long e;
536        char first;
537        int tt;
538        tt = tok.nextToken();
539        if (tt == '(') {
540            logger.debug("weight list");
541            tt = tok.nextToken();
542            while (true) {
543                if (tt == StreamTokenizer.TT_EOF)
544                    break;
545                if (tt == ')')
546                    break;
547                if (tok.sval != null) {
548                    first = tok.sval.charAt(0);
549                    if (digit(first)) {
550                        e = Long.parseLong(tok.sval);
551                        l.add(Long.valueOf(e));
552                        //System.out.println("w: " + e);
553                    }
554                }
555                tt = tok.nextToken(); // also comma
556            }
557        } else {
558            tok.pushBack();
559        }
560        Long[] ol = new Long[1];
561        ol = l.toArray(ol);
562        long[] w = new long[ol.length];
563        for (int i = 0; i < w.length; i++) {
564            w[i] = ol[ol.length - i - 1].longValue();
565        }
566        return w;
567    }
568
569
570    /**
571     * Parsing method for weight array. Syntax:
572     * 
573     * <pre>
574     * ( (w11, ...,w1n), ..., (wm1, ..., wmn) )
575     * </pre>
576     * 
577     * @return the next weight array.
578     * @throws IOException
579     */
580    public long[][] nextWeightArray() throws IOException {
581        List<long[]> l = new ArrayList<long[]>();
582        long[][] w = null;
583        long[] e;
584        char first;
585        int tt;
586        tt = tok.nextToken();
587        if (tt == '(') {
588            logger.debug("weight array");
589            tt = tok.nextToken();
590            while (true) {
591                if (tt == StreamTokenizer.TT_EOF)
592                    break;
593                if (tt == ')')
594                    break;
595                if (tt == '(') {
596                    tok.pushBack();
597                    e = nextWeightList();
598                    l.add(e);
599                    //System.out.println("wa: " + e);
600                } else if (tok.sval != null) {
601                    first = tok.sval.charAt(0);
602                    if (digit(first)) {
603                        tok.pushBack();
604                        tok.pushBack();
605                        e = nextWeightList();
606                        l.add(e);
607                        break;
608                        //System.out.println("w: " + e);
609                    }
610                }
611                tt = tok.nextToken(); // also comma
612            }
613        } else {
614            tok.pushBack();
615        }
616        Object[] ol = l.toArray();
617        w = new long[ol.length][];
618        for (int i = 0; i < w.length; i++) {
619            w[i] = (long[]) ol[i];
620        }
621        return w;
622    }
623
624
625    /**
626     * Parsing method for split index. Syntax:
627     * 
628     * <pre>
629     * |i|
630     * </pre>
631     * 
632     * @return the next split index.
633     * @throws IOException
634     */
635    public int nextSplitIndex() throws IOException {
636        int e = -1; // =unknown
637        int e0 = -1; // =unknown
638        char first;
639        int tt;
640        tt = tok.nextToken();
641        if (tt == '|') {
642            logger.debug("split index");
643            tt = tok.nextToken();
644            if (tt == StreamTokenizer.TT_EOF) {
645                return e;
646            }
647            if (tok.sval != null) {
648                first = tok.sval.charAt(0);
649                if (digit(first)) {
650                    e = Integer.parseInt(tok.sval);
651                    //System.out.println("w: " + i);
652                }
653                tt = tok.nextToken();
654                if (tt != '|') {
655                    tok.pushBack();
656                }
657            }
658        } else if (tt == '[') {
659            logger.debug("split index");
660            tt = tok.nextToken();
661            if (tt == StreamTokenizer.TT_EOF) {
662                return e;
663            }
664            if (tok.sval != null) {
665                first = tok.sval.charAt(0);
666                if (digit(first)) {
667                    e0 = Integer.parseInt(tok.sval);
668                    //System.out.println("w: " + i);
669                }
670                tt = tok.nextToken();
671                if (tt == ',') {
672                    tt = tok.nextToken();
673                    if (tt == StreamTokenizer.TT_EOF) {
674                        return e0;
675                    }
676                    if (tok.sval != null) {
677                        first = tok.sval.charAt(0);
678                        if (digit(first)) {
679                            e = Integer.parseInt(tok.sval);
680                            //System.out.println("w: " + i);
681                        }
682                    }
683                    if (tt != ']') {
684                        tok.pushBack();
685                    }
686                }
687            }
688        } else {
689            tok.pushBack();
690        }
691        return e;
692    }
693
694
695    /**
696     * Parsing method for term order name. Syntax:
697     * 
698     * <pre>
699     * L | IL | LEX | G | IG | GRLEX | W(weights) | '|'split index'|'
700     * </pre>
701     * 
702     * @return the next term order.
703     * @throws IOException
704     */
705    public TermOrder nextTermOrder() throws IOException {
706        int evord = TermOrder.DEFAULT_EVORD;
707        int tt;
708        tt = tok.nextToken();
709        if (tt == StreamTokenizer.TT_EOF) { /* nop */
710        } else if (tt == StreamTokenizer.TT_WORD) {
711            // System.out.println("TT_WORD: " + tok.sval);
712            if (tok.sval != null) {
713                if (tok.sval.equalsIgnoreCase("L")) {
714                    evord = TermOrder.INVLEX;
715                } else if (tok.sval.equalsIgnoreCase("IL")) {
716                    evord = TermOrder.INVLEX;
717                } else if (tok.sval.equalsIgnoreCase("INVLEX")) {
718                    evord = TermOrder.INVLEX;
719                } else if (tok.sval.equalsIgnoreCase("LEX")) {
720                    evord = TermOrder.LEX;
721                } else if (tok.sval.equalsIgnoreCase("G")) {
722                    evord = TermOrder.IGRLEX;
723                } else if (tok.sval.equalsIgnoreCase("IG")) {
724                    evord = TermOrder.IGRLEX;
725                } else if (tok.sval.equalsIgnoreCase("IGRLEX")) {
726                    evord = TermOrder.IGRLEX;
727                } else if (tok.sval.equalsIgnoreCase("GRLEX")) {
728                    evord = TermOrder.GRLEX;
729                } else if (tok.sval.equalsIgnoreCase("REVITDG")) {
730                    evord = TermOrder.REVITDG;
731                } else if (tok.sval.equalsIgnoreCase("W")) {
732                    long[][] w = nextWeightArray();
733                    return new TermOrder(w);
734                }
735            }
736        } else {
737            tok.pushBack();
738        }
739        int s = nextSplitIndex();
740        if (s <= 0) {
741            return new TermOrder(evord);
742        }
743        return new TermOrder(evord, evord, nvars, s);
744    }
745
746
747    /**
748     * Parsing method for solvable polynomial relation table. Syntax:
749     *
750     * <pre>
751     * ( p_1, p_2, p_3, ..., p_{n+1}, p_{n+2}, p_{n+3} )
752     * </pre>
753     *
754     * semantics: <code>p_{n+1} * p_{n+2} = p_{n+3}</code>. The next relation
755     * table is stored into the solvable polynomial factory.
756     * @throws IOException
757     */
758    @SuppressWarnings("unchecked")
759    public void nextRelationTable() throws IOException {
760        if (spfac == null) {
761            return;
762        }
763        RelationTable table = spfac.table;
764        List<GenPolynomial> rels = null;
765        GenPolynomial p;
766        GenSolvablePolynomial sp;
767        int tt;
768        tt = tok.nextToken();
769        logger.debug("start relation table: {}", tt);
770        if (tok.sval != null) {
771            if (tok.sval.equalsIgnoreCase("RelationTable")) {
772                GenPolynomialTokenizer ptok = new GenPolynomialTokenizer(pfac, reader);
773                rels = ptok.nextPolynomialList();
774                ptok = null;
775            }
776        }
777        if (rels == null) {
778            tok.pushBack();
779            return;
780        }
781        for (Iterator<GenPolynomial> it = rels.iterator(); it.hasNext();) {
782            p = it.next();
783            ExpVector e = p.leadingExpVector();
784            if (it.hasNext()) {
785                p = it.next();
786                ExpVector f = p.leadingExpVector();
787                if (it.hasNext()) {
788                    p = it.next();
789                    sp = new GenSolvablePolynomial(spfac);
790                    sp.doPutToMap(p.getMap());
791                    table.update(e, f, sp);
792                }
793            }
794        }
795        if (debug) {
796            logger.info("table = {}", table);
797        }
798        return;
799    }
800
801
802    /**
803     * Parsing method for polynomial ring. Syntax:
804     *
805     * <pre>
806     * coeffRing varList termOrderName (no polyList)
807     * </pre>
808     *
809     * @return the next polynomial ring.
810     * @throws IOException
811     */
812    @SuppressWarnings("unchecked")
813    public GenPolynomialRing nextPolynomialRing() throws IOException {
814        //String comments = "";
815        //comments += nextComment();
816        //if (debug) logger.debug("comment = {}", comments);
817
818        RingFactory coeff = nextCoefficientRing();
819        logger.info("coeff = {}", coeff);
820
821        vars = nextVariableList();
822        final var vv = vars;
823        logger.info("vars = {}", () -> Arrays.toString(vv));
824        if (vars != null) {
825            nvars = vars.length;
826        }
827
828        tord = nextTermOrder();
829        logger.info("tord = {}", tord);
830        // check more TOs
831
832        initFactory(coeff, parsedCoeff); // global: nvars, tord, vars
833        // now pfac is initialized
834        return pfac;
835    }
836
837
838    /**
839     * Parsing method for solvable polynomial ring. Syntax:
840     *
841     * <pre>
842     * varList termOrderName relationTable (no polyList)
843     * </pre>
844     *
845     * @return the next solvable polynomial ring.
846     * @throws IOException
847     */
848    @SuppressWarnings("unchecked")
849    public GenSolvablePolynomialRing nextSolvablePolynomialRing() throws IOException {
850        //String comments = "";
851        //comments += nextComment();
852        //if (debug) logger.debug("comment = {}", comments);
853
854        RingFactory coeff = nextCoefficientRing();
855        logger.info("coeff = {}", coeff.getClass().getSimpleName());
856
857        vars = nextVariableList();
858        logger.info("vars = {}", Arrays.toString(vars));
859        if (vars != null) {
860            nvars = vars.length;
861        }
862
863        tord = nextTermOrder();
864        logger.info("tord = {}", tord);
865        // check more TOs
866
867        initFactory(coeff, parsedCoeff); // must be because of symmetric read
868        initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars
869        //System.out.println("pfac = " + pfac);
870        //System.out.println("spfac = " + spfac);
871
872        nextRelationTable();
873        if (logger.isInfoEnabled()) {
874            logger.info("table = {}", table + ", tok = {}", tok);
875        }
876        // now spfac is initialized
877        return spfac;
878    }
879
880
881    static boolean digit(char x) {
882        return '0' <= x && x <= '9';
883    }
884
885
886    //static boolean letter(char x) {
887    //    return ('a' <= x && x <= 'z') || ('A' <= x && x <= 'Z');
888    //}
889
890
891    // unused
892    public void nextComma() throws IOException {
893        int tt;
894        if (tok.ttype == ',') {
895            tt = tok.nextToken();
896            if (debug) {
897                logger.debug("after comma: {}", tt);
898            }
899        }
900    }
901
902
903    /**
904     * Parsing method for module ring. Syntax:
905     *
906     * <pre>
907     * coeffRing varList termOrderName (no moduleList)
908     * </pre>
909     *
910     * @return the next module ring.
911     * @throws IOException
912     */
913    @SuppressWarnings("unchecked")
914    public GenPolynomialRing nextSubModuleRing() throws IOException {
915        //String comments = "";
916        //comments += nextComment();
917        //if (debug) logger.debug("comment = {}", comments);
918
919        RingFactory coeff = nextCoefficientRing();
920        logger.info("coeff = {}", coeff.getClass().getSimpleName());
921
922        vars = nextVariableList();
923        logger.info("vars = {}", Arrays.toString(vars));
924        if (vars != null) {
925            nvars = vars.length;
926        }
927
928        tord = nextTermOrder();
929        logger.info("tord = {}", tord);
930        // check more TOs
931
932        initFactory(coeff, parsedCoeff); // global: nvars, tord, vars
933        //List<List<GenPolynomial>> m = null;
934        //m = nextSubModuleList();
935        //logger.info("m = {}", m);
936
937        return pfac;
938    }
939
940
941    /**
942     * Parsing method for solvable module ring. Syntax:
943     *
944     * <pre>
945     * varList termOrderName relationTable (no moduleList*)
946     * </pre>
947     *
948     * @return the next solvable module ring.
949     * @throws IOException
950     */
951    @SuppressWarnings("unchecked")
952    public GenSolvablePolynomialRing nextSolvableSubModuleRing() throws IOException {
953        //String comments = "";
954        //comments += nextComment();
955        //if (debug) logger.debug("comment = {}", comments);
956
957        RingFactory coeff = nextCoefficientRing();
958        logger.info("coeff = {}", coeff.getClass().getSimpleName());
959
960        vars = nextVariableList();
961        logger.info("vars = {}", Arrays.toString(vars));
962        if (vars != null) {
963            nvars = vars.length;
964        }
965
966        tord = nextTermOrder();
967        logger.info("tord = {}", tord);
968        // check more TOs
969
970        initFactory(coeff, parsedCoeff); // must be because of symmetric read
971        initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars
972
973        //System.out.println("spfac = " + spfac);
974
975        nextRelationTable();
976        logger.info("table = {}", table);
977
978        //List<List<GenSolvablePolynomial>> s = null;
979        //s = nextSolvableSubModuleList();
980        //logger.info("s = {}", s);
981        //return new OrderedModuleList(spfac, s); // Ordered
982
983        return spfac;
984    }
985
986}