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