001/*
002 * $Id$
003 */
004
005package edu.jas.application;
006
007
008import java.io.BufferedReader;
009import java.io.IOException;
010import java.io.InputStreamReader;
011import java.io.Reader;
012import java.io.StreamTokenizer;
013import java.nio.charset.Charset;
014import java.util.ArrayList;
015import java.util.Arrays;
016import java.util.Iterator;
017import java.util.List;
018import java.util.Scanner;
019
020import org.apache.logging.log4j.Logger;
021import org.apache.logging.log4j.LogManager; 
022
023import edu.jas.arith.BigComplex;
024import edu.jas.arith.BigDecimal;
025import edu.jas.arith.BigInteger;
026import edu.jas.arith.BigQuaternion;
027import edu.jas.arith.BigQuaternionRing;
028import edu.jas.arith.BigRational;
029import edu.jas.arith.ModInteger;
030import edu.jas.arith.ModIntegerRing;
031import edu.jas.arith.ModIntRing;
032import edu.jas.arith.ModLongRing;
033import edu.jas.poly.AlgebraicNumberRing;
034import edu.jas.poly.ExpVector;
035import edu.jas.poly.GenPolynomial;
036import edu.jas.poly.GenPolynomialRing;
037import edu.jas.poly.GenPolynomialTokenizer;
038import edu.jas.poly.GenSolvablePolynomial;
039import edu.jas.poly.GenSolvablePolynomialRing;
040import edu.jas.poly.InvalidExpressionException;
041import edu.jas.poly.RelationTable;
042import edu.jas.poly.TermOrder;
043import edu.jas.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                    logger.debug("pfac = {}", pfac);
481                    GenPolynomialTokenizer ptok = new GenPolynomialTokenizer(pfac, reader);
482                    GenPolynomial mod = ptok.nextPolynomial();
483                    ptok = null;
484                    logger.debug("mod = {}", mod);
485                    pfac = tpfac;
486                    fac = tfac;
487                    vars = ovars;
488                    if (tcfac instanceof ModIntegerRing) {
489                        GenPolynomial<ModInteger> gfmod;
490                        gfmod = (GenPolynomial<ModInteger>) mod;
491                        coeff = new AlgebraicNumberRing<ModInteger>(gfmod);
492                        ct = coeffType.ANmod;
493                    } else {
494                        GenPolynomial<BigRational> anmod;
495                        anmod = (GenPolynomial<BigRational>) mod;
496                        coeff = new AlgebraicNumberRing<BigRational>(anmod);
497                        ct = coeffType.ANrat;
498                    }
499                    logger.debug("coeff = {}", coeff);
500                    tt = tok.nextToken();
501                    if (tt == ']') {
502                        //ok, no nextToken();
503                    } else {
504                        tok.pushBack();
505                    }
506                } else {
507                    tok.pushBack();
508                }
509            }
510        }
511        if (coeff == null) {
512            tok.pushBack();
513            coeff = new BigRational();
514            ct = coeffType.BigRat;
515        }
516        parsedCoeff = ct;
517        return coeff;
518    }
519
520
521    /**
522     * Parsing method for weight list. Syntax:
523     * 
524     * <pre>
525     * (w1, w2, w3, ..., wn)
526     * </pre>
527     * 
528     * @return the next weight list.
529     * @throws IOException
530     */
531    public long[] nextWeightList() throws IOException {
532        List<Long> l = new ArrayList<Long>();
533        long e;
534        char first;
535        int tt;
536        tt = tok.nextToken();
537        if (tt == '(') {
538            logger.debug("weight list");
539            tt = tok.nextToken();
540            while (true) {
541                if (tt == StreamTokenizer.TT_EOF)
542                    break;
543                if (tt == ')')
544                    break;
545                if (tok.sval != null) {
546                    first = tok.sval.charAt(0);
547                    if (digit(first)) {
548                        e = Long.parseLong(tok.sval);
549                        l.add(Long.valueOf(e));
550                        //System.out.println("w: " + e);
551                    }
552                }
553                tt = tok.nextToken(); // also comma
554            }
555        } else {
556            tok.pushBack();
557        }
558        Long[] ol = new Long[1];
559        ol = l.toArray(ol);
560        long[] w = new long[ol.length];
561        for (int i = 0; i < w.length; i++) {
562            w[i] = ol[ol.length - i - 1].longValue();
563        }
564        return w;
565    }
566
567
568    /**
569     * Parsing method for weight array. Syntax:
570     * 
571     * <pre>
572     * ( (w11, ...,w1n), ..., (wm1, ..., wmn) )
573     * </pre>
574     * 
575     * @return the next weight array.
576     * @throws IOException
577     */
578    public long[][] nextWeightArray() throws IOException {
579        List<long[]> l = new ArrayList<long[]>();
580        long[][] w = null;
581        long[] e;
582        char first;
583        int tt;
584        tt = tok.nextToken();
585        if (tt == '(') {
586            logger.debug("weight array");
587            tt = tok.nextToken();
588            while (true) {
589                if (tt == StreamTokenizer.TT_EOF)
590                    break;
591                if (tt == ')')
592                    break;
593                if (tt == '(') {
594                    tok.pushBack();
595                    e = nextWeightList();
596                    l.add(e);
597                    //System.out.println("wa: " + e);
598                } else if (tok.sval != null) {
599                    first = tok.sval.charAt(0);
600                    if (digit(first)) {
601                        tok.pushBack();
602                        tok.pushBack();
603                        e = nextWeightList();
604                        l.add(e);
605                        break;
606                        //System.out.println("w: " + e);
607                    }
608                }
609                tt = tok.nextToken(); // also comma
610            }
611        } else {
612            tok.pushBack();
613        }
614        Object[] ol = l.toArray();
615        w = new long[ol.length][];
616        for (int i = 0; i < w.length; i++) {
617            w[i] = (long[]) ol[i];
618        }
619        return w;
620    }
621
622
623    /**
624     * Parsing method for split index. Syntax:
625     * 
626     * <pre>
627     * |i|
628     * </pre>
629     * 
630     * @return the next split index.
631     * @throws IOException
632     */
633    public int nextSplitIndex() throws IOException {
634        int e = -1; // =unknown
635        int e0 = -1; // =unknown
636        char first;
637        int tt;
638        tt = tok.nextToken();
639        if (tt == '|') {
640            logger.debug("split index");
641            tt = tok.nextToken();
642            if (tt == StreamTokenizer.TT_EOF) {
643                return e;
644            }
645            if (tok.sval != null) {
646                first = tok.sval.charAt(0);
647                if (digit(first)) {
648                    e = Integer.parseInt(tok.sval);
649                    //System.out.println("w: " + i);
650                }
651                tt = tok.nextToken();
652                if (tt != '|') {
653                    tok.pushBack();
654                }
655            }
656        } else if (tt == '[') {
657            logger.debug("split index");
658            tt = tok.nextToken();
659            if (tt == StreamTokenizer.TT_EOF) {
660                return e;
661            }
662            if (tok.sval != null) {
663                first = tok.sval.charAt(0);
664                if (digit(first)) {
665                    e0 = Integer.parseInt(tok.sval);
666                    //System.out.println("w: " + i);
667                }
668                tt = tok.nextToken();
669                if (tt == ',') {
670                    tt = tok.nextToken();
671                    if (tt == StreamTokenizer.TT_EOF) {
672                        return e0;
673                    }
674                    if (tok.sval != null) {
675                        first = tok.sval.charAt(0);
676                        if (digit(first)) {
677                            e = Integer.parseInt(tok.sval);
678                            //System.out.println("w: " + i);
679                        }
680                    }
681                    if (tt != ']') {
682                        tok.pushBack();
683                    }
684                }
685            }
686        } else {
687            tok.pushBack();
688        }
689        return e;
690    }
691
692
693    /**
694     * Parsing method for term order name. Syntax:
695     * 
696     * <pre>
697     * L | IL | LEX | G | IG | GRLEX | W(weights) | '|'split index'|'
698     * </pre>
699     * 
700     * @return the next term order.
701     * @throws IOException
702     */
703    public TermOrder nextTermOrder() throws IOException {
704        int evord = TermOrder.DEFAULT_EVORD;
705        int tt;
706        tt = tok.nextToken();
707        if (tt == StreamTokenizer.TT_EOF) { /* nop */
708        } else if (tt == StreamTokenizer.TT_WORD) {
709            // System.out.println("TT_WORD: " + tok.sval);
710            if (tok.sval != null) {
711                if (tok.sval.equalsIgnoreCase("L")) {
712                    evord = TermOrder.INVLEX;
713                } else if (tok.sval.equalsIgnoreCase("IL")) {
714                    evord = TermOrder.INVLEX;
715                } else if (tok.sval.equalsIgnoreCase("INVLEX")) {
716                    evord = TermOrder.INVLEX;
717                } else if (tok.sval.equalsIgnoreCase("LEX")) {
718                    evord = TermOrder.LEX;
719                } else if (tok.sval.equalsIgnoreCase("G")) {
720                    evord = TermOrder.IGRLEX;
721                } else if (tok.sval.equalsIgnoreCase("IG")) {
722                    evord = TermOrder.IGRLEX;
723                } else if (tok.sval.equalsIgnoreCase("IGRLEX")) {
724                    evord = TermOrder.IGRLEX;
725                } else if (tok.sval.equalsIgnoreCase("GRLEX")) {
726                    evord = TermOrder.GRLEX;
727                } else if (tok.sval.equalsIgnoreCase("REVITDG")) {
728                    evord = TermOrder.REVITDG;
729                } else if (tok.sval.equalsIgnoreCase("W")) {
730                    long[][] w = nextWeightArray();
731                    return new TermOrder(w);
732                }
733            }
734        } else {
735            tok.pushBack();
736        }
737        int s = nextSplitIndex();
738        if (s <= 0) {
739            return new TermOrder(evord);
740        }
741        return new TermOrder(evord, evord, nvars, s);
742    }
743
744
745    /**
746     * Parsing method for solvable polynomial relation table. Syntax:
747     * 
748     * <pre>
749     * ( p_1, p_2, p_3, ..., p_{n+1}, p_{n+2}, p_{n+3} )
750     * </pre>
751     * 
752     * semantics: <code>p_{n+1} * p_{n+2} = p_{n+3}</code>. The next relation
753     * table is stored into the solvable polynomial factory.
754     * @throws IOException
755     */
756    @SuppressWarnings("unchecked")
757    public void nextRelationTable() throws IOException {
758        if (spfac == null) {
759            return;
760        }
761        RelationTable table = spfac.table;
762        List<GenPolynomial> rels = null;
763        GenPolynomial p;
764        GenSolvablePolynomial sp;
765        int tt;
766        tt = tok.nextToken();
767        logger.debug("start relation table: {}", tt);
768        if (tok.sval != null) {
769            if (tok.sval.equalsIgnoreCase("RelationTable")) {
770                GenPolynomialTokenizer ptok = new GenPolynomialTokenizer(pfac, reader);
771                rels = ptok.nextPolynomialList();
772                ptok = null;
773            }
774        }
775        if (rels == null) {
776            tok.pushBack();
777            return;
778        }
779        for (Iterator<GenPolynomial> it = rels.iterator(); it.hasNext();) {
780            p = it.next();
781            ExpVector e = p.leadingExpVector();
782            if (it.hasNext()) {
783                p = it.next();
784                ExpVector f = p.leadingExpVector();
785                if (it.hasNext()) {
786                    p = it.next();
787                    sp = new GenSolvablePolynomial(spfac);
788                    sp.doPutToMap(p.getMap());
789                    table.update(e, f, sp);
790                }
791            }
792        }
793        if (debug) {
794            logger.info("table = {}", table);
795        }
796        return;
797    }
798
799
800    /**
801     * Parsing method for polynomial ring. Syntax:
802     * 
803     * <pre>
804     * coeffRing varList termOrderName polyList
805     * </pre>
806     * 
807     * @return the next polynomial ring.
808     * @throws IOException
809     */
810    @SuppressWarnings("unchecked")
811    public GenPolynomialRing nextPolynomialRing() throws IOException {
812        //String comments = "";
813        //comments += nextComment();
814        //if (debug) logger.debug("comment = {}", comments);
815
816        RingFactory coeff = nextCoefficientRing();
817        logger.info("coeff = {}", coeff);
818
819        vars = nextVariableList();
820        final var vv = vars;
821        logger.info("vars = {}", () -> Arrays.toString(vv));
822        if (vars != null) {
823            nvars = vars.length;
824        }
825
826        tord = nextTermOrder();
827        logger.info("tord = {}", tord);
828        // check more TOs
829
830        initFactory(coeff, parsedCoeff); // global: nvars, tord, vars
831        // now pfac is initialized
832        return pfac;
833    }
834
835
836    /**
837     * Parsing method for solvable polynomial ring. Syntax:
838     * 
839     * <pre>
840     * varList termOrderName relationTable polyList
841     * </pre>
842     * 
843     * @return the next solvable polynomial ring.
844     * @throws IOException
845     */
846    @SuppressWarnings("unchecked")
847    public GenSolvablePolynomialRing nextSolvablePolynomialRing() throws IOException {
848        //String comments = "";
849        //comments += nextComment();
850        //if (debug) logger.debug("comment = {}", comments);
851
852        RingFactory coeff = nextCoefficientRing();
853        logger.info("coeff = {}", coeff.getClass().getSimpleName());
854
855        vars = nextVariableList();
856        logger.info("vars = {}", Arrays.toString(vars));
857        if (vars != null) {
858            nvars = vars.length;
859        }
860
861        tord = nextTermOrder();
862        logger.info("tord = {}", tord);
863        // check more TOs
864
865        initFactory(coeff, parsedCoeff); // must be because of symmetric read
866        initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars
867        //System.out.println("pfac = " + pfac);
868        //System.out.println("spfac = " + spfac);
869
870        nextRelationTable();
871        if (logger.isInfoEnabled()) {
872            logger.info("table = {}", table + ", tok = {}", tok);
873        }
874        // now spfac is initialized
875        return spfac;
876    }
877
878
879    static boolean digit(char x) {
880        return '0' <= x && x <= '9';
881    }
882
883
884    //static boolean letter(char x) {
885    //    return ('a' <= x && x <= 'z') || ('A' <= x && x <= 'Z');
886    //}
887
888
889    // unused
890    public void nextComma() throws IOException {
891        int tt;
892        if (tok.ttype == ',') {
893            tt = tok.nextToken();
894            if (debug) {
895                logger.debug("after comma: {}", tt);
896            }
897        }
898    }
899
900
901    /**
902     * Parse variable list from String.
903     * @param s String. Syntax:
904     * 
905     *            <pre>
906     * (n1,...,nk)
907     *            </pre>
908     * 
909     *            or
910     * 
911     *            <pre>
912     * (n1 ... nk)
913     *            </pre>
914     * 
915     *            parenthesis are optional.
916     * @return array of variable names found in s.
917     */
918    public static String[] variableList(String s) {
919        String[] vl = null;
920        if (s == null) {
921            return vl;
922        }
923        String st = s.trim();
924        if (st.length() == 0) {
925            return new String[0];
926        }
927        if (st.charAt(0) == '(') {
928            st = st.substring(1);
929        }
930        if (st.charAt(st.length() - 1) == ')') {
931            st = st.substring(0, st.length() - 1);
932        }
933        st = st.replaceAll(",", " ");
934        List<String> sl = new ArrayList<String>();
935        Scanner sc = new Scanner(st);
936        while (sc.hasNext()) {
937            String sn = sc.next();
938            sl.add(sn);
939        }
940        sc.close();
941        vl = new String[sl.size()];
942        int i = 0;
943        for (String si : sl) {
944            vl[i] = si;
945            i++;
946        }
947        return vl;
948    }
949
950}