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