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