001/* 002 * $Id: GenPolynomialTokenizer.java 5919 2018-09-16 21:30:15Z kredel $ 003 */ 004 005package edu.jas.poly; 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; 019import java.util.Set; 020import java.util.TreeSet; 021 022import org.apache.logging.log4j.Logger; 023import org.apache.logging.log4j.LogManager; 024 025import edu.jas.arith.BigComplex; 026import edu.jas.arith.BigDecimal; 027import edu.jas.arith.BigInteger; 028import edu.jas.arith.BigQuaternion; 029import edu.jas.arith.BigQuaternionRing; 030import edu.jas.arith.BigOctonion; 031import edu.jas.arith.BigRational; 032import edu.jas.arith.ModInteger; 033import edu.jas.arith.ModIntegerRing; 034import edu.jas.arith.ModLongRing; 035import edu.jas.arith.ModIntRing; 036import edu.jas.structure.RingElem; 037import edu.jas.structure.RingFactory; 038 039 040/** 041 * GenPolynomial Tokenizer. Used to read rational polynomials and lists of 042 * polynomials from input streams. Arbitrary polynomial rings and coefficient 043 * rings can be read with RingFactoryTokenizer. <b>Note:</b> Can no more read 044 * QuotientRing since end of 2010, revision 3441. Quotient coefficients and 045 * others can still be read if the respective factory is provided via the 046 * constructor. 047 * @see edu.jas.application.RingFactoryTokenizer 048 * @author Heinz Kredel 049 */ 050public class GenPolynomialTokenizer { 051 052 053 private static final Logger logger = LogManager.getLogger(GenPolynomialTokenizer.class); 054 055 056 private static final boolean debug = logger.isDebugEnabled(); 057 058 059 private String[] vars; 060 061 062 private int nvars = 1; 063 064 065 private TermOrder tord; 066 067 068 private RelationTable table; 069 070 071 private final StreamTokenizer tok; 072 073 074 private final Reader reader; 075 076 077 private RingFactory fac; 078 079 080 private static enum coeffType { 081 BigRat, BigInt, ModInt, BigC, BigQ, BigO, BigD, ANrat, ANmod, IntFunc 082 }; 083 084 085 private coeffType parsedCoeff = coeffType.BigRat; 086 087 088 private GenPolynomialRing pfac; 089 090 091 private static enum polyType { 092 PolBigRat, PolBigInt, PolModInt, PolBigC, PolBigD, PolBigQ, PolBigO, PolANrat, PolANmod, PolIntFunc 093 }; 094 095 096 @SuppressWarnings("unused") 097 private polyType parsedPoly = polyType.PolBigRat; 098 099 100 private GenSolvablePolynomialRing spfac; 101 102 103 /** 104 * No-args constructor reads from System.in. 105 */ 106 public GenPolynomialTokenizer() { 107 this(new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF8")))); 108 } 109 110 111 /** 112 * Constructor with Ring and Reader. 113 * @param rf ring factory. 114 * @param r reader stream. 115 */ 116 public GenPolynomialTokenizer(GenPolynomialRing rf, Reader r) { 117 this(r); 118 if (rf == null) { 119 return; 120 } 121 if (rf instanceof GenSolvablePolynomialRing) { 122 pfac = rf; 123 spfac = (GenSolvablePolynomialRing) rf; 124 } else { 125 pfac = rf; 126 spfac = null; 127 } 128 fac = rf.coFac; 129 vars = rf.vars; 130 if (vars != null) { 131 nvars = vars.length; 132 } 133 tord = rf.tord; 134 // relation table 135 if (spfac != null) { 136 table = spfac.table; 137 } else { 138 table = null; 139 } 140 } 141 142 143 /** 144 * Constructor with Reader. 145 * @param r reader stream. 146 */ 147 @SuppressWarnings("unchecked") 148 public GenPolynomialTokenizer(Reader r) { 149 vars = null; 150 tord = new TermOrder(); 151 nvars = 1; 152 fac = new BigRational(1); 153 154 pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars); 155 spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars); 156 157 reader = r; 158 tok = new StreamTokenizer(reader); 159 tok.resetSyntax(); 160 // tok.eolIsSignificant(true); no more 161 tok.eolIsSignificant(false); 162 tok.wordChars('0', '9'); 163 tok.wordChars('a', 'z'); 164 tok.wordChars('A', 'Z'); 165 tok.wordChars('_', '_'); // for subscripts x_i 166 tok.wordChars('/', '/'); // wg. rational numbers 167 tok.wordChars('.', '.'); // wg. floats 168 tok.wordChars('~', '~'); // wg. quaternions 169 tok.wordChars(128 + 32, 255); 170 tok.whitespaceChars(0, ' '); 171 tok.commentChar('#'); 172 tok.quoteChar('"'); 173 tok.quoteChar('\''); 174 //tok.slashStarComments(true); does not work 175 176 } 177 178 179 /** 180 * Initialize coefficient and polynomial factories. 181 * @param rf ring factory. 182 * @param ct coefficient type. 183 */ 184 @SuppressWarnings("unchecked") 185 public void initFactory(RingFactory rf, coeffType ct) { 186 fac = rf; 187 parsedCoeff = ct; 188 189 switch (ct) { 190 case BigRat: 191 pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars); 192 parsedPoly = polyType.PolBigRat; 193 break; 194 case BigInt: 195 pfac = new GenPolynomialRing<BigInteger>(fac, nvars, tord, vars); 196 parsedPoly = polyType.PolBigInt; 197 break; 198 case ModInt: 199 pfac = new GenPolynomialRing<ModInteger>(fac, nvars, tord, vars); 200 parsedPoly = polyType.PolModInt; 201 break; 202 case BigC: 203 pfac = new GenPolynomialRing<BigComplex>(fac, nvars, tord, vars); 204 parsedPoly = polyType.PolBigC; 205 break; 206 case BigQ: 207 pfac = new GenPolynomialRing<BigQuaternion>(fac, nvars, tord, vars); 208 parsedPoly = polyType.PolBigQ; 209 break; 210 case BigO: 211 pfac = new GenPolynomialRing<BigOctonion>(fac, nvars, tord, vars); 212 parsedPoly = polyType.PolBigO; 213 break; 214 case BigD: 215 pfac = new GenPolynomialRing<BigDecimal>(fac, nvars, tord, vars); 216 parsedPoly = polyType.PolBigD; 217 break; 218 case IntFunc: 219 pfac = new GenPolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars); 220 parsedPoly = polyType.PolIntFunc; 221 break; 222 default: 223 pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars); 224 parsedPoly = polyType.PolBigRat; 225 } 226 } 227 228 229 /** 230 * Initialize coefficient and solvable polynomial factories. 231 * @param rf ring factory. 232 * @param ct coefficient type. 233 */ 234 @SuppressWarnings("unchecked") 235 public void initSolvableFactory(RingFactory rf, coeffType ct) { 236 fac = rf; 237 parsedCoeff = ct; 238 239 switch (ct) { 240 case BigRat: 241 spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars); 242 parsedPoly = polyType.PolBigRat; 243 break; 244 case BigInt: 245 spfac = new GenSolvablePolynomialRing<BigInteger>(fac, nvars, tord, vars); 246 parsedPoly = polyType.PolBigInt; 247 break; 248 case ModInt: 249 spfac = new GenSolvablePolynomialRing<ModInteger>(fac, nvars, tord, vars); 250 parsedPoly = polyType.PolModInt; 251 break; 252 case BigC: 253 spfac = new GenSolvablePolynomialRing<BigComplex>(fac, nvars, tord, vars); 254 parsedPoly = polyType.PolBigC; 255 break; 256 case BigQ: 257 spfac = new GenSolvablePolynomialRing<BigQuaternion>(fac, nvars, tord, vars); 258 parsedPoly = polyType.PolBigQ; 259 break; 260 case BigO: 261 spfac = new GenSolvablePolynomialRing<BigOctonion>(fac, nvars, tord, vars); 262 parsedPoly = polyType.PolBigO; 263 break; 264 case BigD: 265 spfac = new GenSolvablePolynomialRing<BigDecimal>(fac, nvars, tord, vars); 266 parsedPoly = polyType.PolBigD; 267 break; 268 case IntFunc: 269 spfac = new GenSolvablePolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars); 270 parsedPoly = polyType.PolIntFunc; 271 break; 272 default: 273 spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars); 274 parsedPoly = polyType.PolBigRat; 275 } 276 } 277 278 279 /** 280 * Parsing method for GenPolynomial. Syntax depends also on the syntax of 281 * the coefficients, as the respective parser is used. Basic term/monomial 282 * syntax: 283 * 284 * <pre> 285 ... coefficient variable**exponent ... variable^exponent + ... - .... 286 * </pre> 287 * 288 * Juxtaposition means multiplication <code>*</code>. Then terms/monomials 289 * can be added or subtracted <code>+, -</code> and grouped by parenthesis 290 * <code>()</code>. There are some heuristics to detect when a coefficient 291 * should be parsed. To force parsing of a coefficient enclose it in braces 292 * <code>{}</code>. 293 * @return the next polynomial. 294 * @throws IOException 295 */ 296 @SuppressWarnings("unchecked") 297 public GenPolynomial nextPolynomial() throws IOException { 298 if (debug) { 299 logger.debug("torder = " + tord); 300 } 301 GenPolynomial a = pfac.getZERO(); 302 GenPolynomial a1 = pfac.getONE(); 303 ExpVector leer = pfac.evzero; 304 305 if (debug) { 306 logger.debug("a = " + a); 307 logger.debug("a1 = " + a1); 308 } 309 GenPolynomial b = a1; 310 GenPolynomial c; 311 int tt; //, oldtt; 312 //String rat = ""; 313 char first; 314 RingElem r; 315 ExpVector e; 316 int ix; 317 long ie; 318 while (true) { 319 // next input. determine next action 320 tt = tok.nextToken(); 321 //System.out.println("while tt = " + tok); 322 logger.debug("while tt = " + tok); 323 if (tt == StreamTokenizer.TT_EOF) 324 break; 325 switch (tt) { 326 case ')': 327 case ',': 328 return a; // do not change or remove 329 case '-': 330 b = b.negate(); 331 case '+': 332 case '*': 333 tt = tok.nextToken(); 334 break; 335 default: // skip 336 } 337 // read coefficient, monic monomial and polynomial 338 if (tt == StreamTokenizer.TT_EOF) 339 break; 340 switch (tt) { 341 // case '_': removed 342 case '}': 343 throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b); 344 case '{': // recursion 345 StringBuffer rf = new StringBuffer(); 346 int level = 0; 347 do { 348 tt = tok.nextToken(); 349 //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level); 350 if (tt == StreamTokenizer.TT_EOF) { 351 throw new InvalidExpressionException( 352 "mismatch of braces after " + a + ", error at " + b); 353 } 354 if (tt == '{') { 355 level++; 356 } 357 if (tt == '}') { 358 level--; 359 if (level < 0) { 360 continue; // skip last closing brace 361 } 362 } 363 if (tok.sval != null) { 364 if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') { 365 rf.append(" "); 366 } 367 rf.append(tok.sval); // " " + 368 } else { 369 rf.append((char) tt); 370 } 371 } while (level >= 0); 372 //System.out.println("coeff{} = " + rf.toString() ); 373 try { 374 r = (RingElem) fac.parse(rf.toString()); 375 } catch (NumberFormatException re) { 376 throw new InvalidExpressionException("not a number " + rf, re); 377 } 378 if (debug) 379 logger.debug("coeff " + r); 380 ie = nextExponent(); 381 if (debug) 382 logger.debug("ie " + ie); 383 r = (RingElem) r.power(ie); //Power.<RingElem> positivePower(r, ie); 384 if (debug) 385 logger.debug("coeff^ie " + r); 386 b = b.multiply(r, leer); 387 tt = tok.nextToken(); 388 if (debug) 389 logger.debug("tt,digit = " + tok); 390 //no break; 391 break; 392 393 //case '.': // eventually a float 394 //System.out.println("start . = " + reader); 395 //throw new InvalidExpressionException("float must start with a digit "); 396 397 case StreamTokenizer.TT_WORD: 398 //System.out.println("TT_WORD: " + tok.sval); 399 if (tok.sval == null || tok.sval.length() == 0) 400 break; 401 // read coefficient 402 first = tok.sval.charAt(0); 403 if (digit(first) || first == '/' || first == '.' || first == '~') { 404 //System.out.println("coeff 0 = " + tok.sval ); 405 StringBuffer df = new StringBuffer(); 406 df.append(tok.sval); 407 if (tok.sval.length() > 1 && digit(tok.sval.charAt(1))) { 408 //System.out.println("start / or . = " + tok.sval); 409 if (first == '/') { // let x/2 be x 1/2 410 df.insert(0, "1"); 411 } 412 if (first == '.') { // let x.2 be x 0.2 413 df.insert(0, "0"); 414 } 415 } 416 if (tok.sval.charAt(tok.sval.length() - 1) == 'i') { // complex number 417 tt = tok.nextToken(); 418 if (debug) 419 logger.debug("tt,im = " + tok); 420 if (tok.sval != null || tt == '-') { 421 if (tok.sval != null) { 422 df.append(tok.sval); 423 } else { 424 df.append("-"); 425 } 426 if (tt == '-') { 427 tt = tok.nextToken(); // todo: decimal number 428 if (tok.sval != null && digit(tok.sval.charAt(0))) { 429 df.append(tok.sval); 430 431 } else { 432 tok.pushBack(); 433 } 434 } 435 } else { 436 tok.pushBack(); 437 } 438 } 439 tt = tok.nextToken(); 440 if (tt == '.') { // decimal number, obsolete by word char? 441 tt = tok.nextToken(); 442 if (debug) 443 logger.debug("tt,dot = " + tok); 444 if (tok.sval != null) { 445 df.append("."); 446 df.append(tok.sval); 447 } else { 448 tok.pushBack(); 449 tok.pushBack(); 450 } 451 } else { 452 tok.pushBack(); 453 } 454 try { 455 //System.out.println("df = " + df + ", fac = " + fac.getClass()); 456 r = (RingElem) fac.parse(df.toString()); 457 //System.out.println("r = " + r); 458 } catch (NumberFormatException re) { 459 //System.out.println("re = " + re); 460 throw new InvalidExpressionException("not a number " + df, re); 461 } 462 if (debug) 463 logger.debug("coeff " + r); 464 //System.out.println("r = " + r.toScriptFactory()); 465 ie = nextExponent(); 466 if (debug) 467 logger.debug("ie " + ie); 468 // r = r^ie; 469 r = (RingElem) r.power(ie); //Power.<RingElem> positivePower(r, ie); 470 if (debug) 471 logger.debug("coeff^ie " + r); 472 b = b.multiply(r, leer); 473 tt = tok.nextToken(); 474 if (debug) 475 logger.debug("tt,digit = " + tok); 476 } 477 if (tt == StreamTokenizer.TT_EOF) 478 break; 479 if (tok.sval == null) 480 break; 481 // read monomial or recursion 482 first = tok.sval.charAt(0); 483 if (letter(first)) { 484 ix = leer.indexVar(tok.sval, vars); //indexVar( tok.sval ); 485 if (ix < 0) { // not found 486 try { 487 r = (RingElem) fac.parse(tok.sval); 488 } catch (NumberFormatException re) { 489 throw new InvalidExpressionException("recursively unknown variable " + tok.sval); 490 } 491 if (debug) 492 logger.info("coeff " + r); 493 //if (r.isONE() || r.isZERO()) { 494 //logger.error("Unknown varibable " + tok.sval); 495 //break; 496 //throw new InvalidExpressionException("recursively unknown variable " + tok.sval); 497 //} 498 ie = nextExponent(); 499 // System.out.println("ie: " + ie); 500 r = (RingElem) r.power(ie); //Power.<RingElem> positivePower(r, ie); 501 b = b.multiply(r); 502 } else { // found 503 // System.out.println("ix: " + ix); 504 ie = nextExponent(); 505 // System.out.println("ie: " + ie); 506 e = ExpVector.create(vars.length, ix, ie); 507 b = b.multiply(e); 508 } 509 tt = tok.nextToken(); 510 if (debug) 511 logger.debug("tt,letter = " + tok); 512 } 513 break; 514 515 case '(': 516 c = nextPolynomial(); 517 if (debug) 518 logger.debug("factor " + c); 519 ie = nextExponent(); 520 if (debug) 521 logger.debug("ie " + ie); 522 c = (GenPolynomial) c.power(ie); //Power.<GenPolynomial> positivePower(c, ie); 523 if (debug) 524 logger.debug("factor^ie " + c); 525 b = b.multiply(c); 526 tt = tok.nextToken(); 527 if (debug) 528 logger.debug("tt,digit = " + tok); 529 //no break; 530 break; 531 532 default: //skip 533 } 534 if (tt == StreamTokenizer.TT_EOF) 535 break; 536 // complete polynomial 537 tok.pushBack(); 538 switch (tt) { 539 case '-': 540 case '+': 541 case ')': 542 case ',': 543 logger.debug("b, = " + b); 544 a = a.sum(b); 545 b = a1; 546 break; 547 case '*': 548 logger.debug("b, = " + b); 549 //a = a.sum(b); 550 //b = a1; 551 break; 552 case '\n': 553 tt = tok.nextToken(); 554 if (debug) 555 logger.debug("tt,nl = " + tt); 556 break; 557 default: // skip or finish ? 558 if (debug) 559 logger.debug("default: " + tok); 560 } 561 } 562 if (debug) 563 logger.debug("b = " + b); 564 a = a.sum(b); 565 if (debug) 566 logger.debug("a = " + a); 567 // b = a1; 568 return a; 569 } 570 571 572 /** 573 * Parsing method for exponent (of variable). Syntax: 574 * 575 * <pre> 576 * ^long | **long 577 * </pre> 578 * 579 * @return the next exponent or 1. 580 * @throws IOException 581 */ 582 public long nextExponent() throws IOException { 583 long e = 1; 584 char first; 585 int tt; 586 tt = tok.nextToken(); 587 if (tt == '^') { 588 if (debug) 589 logger.debug("exponent ^"); 590 tt = tok.nextToken(); 591 if (tok.sval != null) { 592 first = tok.sval.charAt(0); 593 if (digit(first)) { 594 e = Long.parseLong(tok.sval); 595 return e; 596 } 597 } 598 } 599 if (tt == '*') { 600 tt = tok.nextToken(); 601 if (tt == '*') { 602 if (debug) 603 logger.debug("exponent **"); 604 tt = tok.nextToken(); 605 if (tok.sval != null) { 606 first = tok.sval.charAt(0); 607 if (digit(first)) { 608 e = Long.parseLong(tok.sval); 609 return e; 610 } 611 } 612 } 613 tok.pushBack(); 614 } 615 tok.pushBack(); 616 return e; 617 } 618 619 620 /** 621 * Parsing method for comments. Syntax: 622 * 623 * <pre> 624 * (* comment *) | /_* comment *_/ 625 * </pre> 626 * 627 * without <code>_</code>. Unused, as it does not work with this pushBack(). 628 */ 629 public String nextComment() throws IOException { 630 // syntax: (* comment *) | /* comment */ 631 StringBuffer c = new StringBuffer(); 632 int tt; 633 if (debug) 634 logger.debug("comment: " + tok); 635 tt = tok.nextToken(); 636 if (debug) 637 logger.debug("comment: " + tok); 638 if (tt == '(') { 639 tt = tok.nextToken(); 640 if (debug) 641 logger.debug("comment: " + tok); 642 if (tt == '*') { 643 if (debug) 644 logger.debug("comment: "); 645 while (true) { 646 tt = tok.nextToken(); 647 if (tt == '*') { 648 tt = tok.nextToken(); 649 if (tt == ')') { 650 return c.toString(); 651 } 652 tok.pushBack(); 653 } 654 c.append(tok.sval); 655 } 656 } 657 tok.pushBack(); 658 if (debug) 659 logger.debug("comment: " + tok); 660 } 661 tok.pushBack(); 662 if (debug) 663 logger.debug("comment: " + tok); 664 return c.toString(); 665 } 666 667 668 /** 669 * Parsing method for variable list. Syntax: 670 * 671 * <pre> 672 * (a, b c, de) 673 * </pre> 674 * 675 * gives <code>[ "a", "b", "c", "de" ]</code> 676 * @return the next variable list. 677 * @throws IOException 678 */ 679 public String[] nextVariableList() throws IOException { 680 List<String> l = new ArrayList<String>(); 681 int tt; 682 tt = tok.nextToken(); 683 //System.out.println("vList tok = " + tok); 684 if (tt == '(' || tt == '{') { 685 logger.debug("variable list"); 686 tt = tok.nextToken(); 687 while (true) { 688 if (tt == StreamTokenizer.TT_EOF) 689 break; 690 if (tt == ')' || tt == '}') 691 break; 692 if (tt == StreamTokenizer.TT_WORD) { 693 //System.out.println("TT_WORD: " + tok.sval); 694 l.add(tok.sval); 695 } 696 tt = tok.nextToken(); 697 } 698 } else { 699 tok.pushBack(); 700 } 701 Object[] ol = l.toArray(); 702 String[] v = new String[ol.length]; 703 for (int i = 0; i < v.length; i++) { 704 v[i] = (String) ol[i]; 705 } 706 return v; 707 } 708 709 710 /** 711 * Parsing method for coefficient ring. Syntax: 712 * 713 * <pre> 714 * Rat | Q | Int | Z | Mod modul | Complex | C | D | Quat | AN[ (var) ( poly ) ] | AN[ modul (var) ( poly ) ] | IntFunc (var_list) 715 * </pre> 716 * 717 * @return the next coefficient factory. 718 * @throws IOException 719 */ 720 @SuppressWarnings({ "unchecked", "cast" }) 721 public RingFactory nextCoefficientRing() throws IOException { 722 RingFactory coeff = null; 723 coeffType ct = null; 724 int tt; 725 tt = tok.nextToken(); 726 if (tok.sval != null) { 727 if (tok.sval.equalsIgnoreCase("Q")) { 728 coeff = new BigRational(0); 729 ct = coeffType.BigRat; 730 } else if (tok.sval.equalsIgnoreCase("Rat")) { 731 coeff = new BigRational(0); 732 ct = coeffType.BigRat; 733 } else if (tok.sval.equalsIgnoreCase("D")) { 734 coeff = new BigDecimal(0); 735 ct = coeffType.BigD; 736 } else if (tok.sval.equalsIgnoreCase("Z")) { 737 coeff = new BigInteger(0); 738 ct = coeffType.BigInt; 739 } else if (tok.sval.equalsIgnoreCase("Int")) { 740 coeff = new BigInteger(0); 741 ct = coeffType.BigInt; 742 } else if (tok.sval.equalsIgnoreCase("C")) { 743 coeff = new BigComplex(0); 744 ct = coeffType.BigC; 745 } else if (tok.sval.equalsIgnoreCase("Complex")) { 746 coeff = new BigComplex(0); 747 ct = coeffType.BigC; 748 } else if (tok.sval.equalsIgnoreCase("Quat")) { 749 logger.warn("parse of quaternion coefficients may fail for negative components (use ~ for -)"); 750 coeff = new BigQuaternionRing(); 751 ct = coeffType.BigQ; 752 } else if (tok.sval.equalsIgnoreCase("Oct")) { 753 logger.warn("parse of octonion coefficients may fail for negative components (use ~ for -)"); 754 coeff = new BigOctonion(new BigQuaternionRing()); 755 ct = coeffType.BigO; 756 } else if (tok.sval.equalsIgnoreCase("Mod")) { 757 tt = tok.nextToken(); 758 boolean openb = false; 759 if (tt == '[') { // optional 760 openb = true; 761 tt = tok.nextToken(); 762 } 763 if (tok.sval != null && tok.sval.length() > 0) { 764 if (digit(tok.sval.charAt(0))) { 765 BigInteger mo = new BigInteger(tok.sval); 766 BigInteger lm = new BigInteger(ModLongRing.MAX_LONG); //wrong: Long.MAX_VALUE); 767 if (mo.compareTo(lm) < 0) { 768 if (mo.compareTo(new BigInteger(ModIntRing.MAX_INT)) < 0) { 769 coeff = new ModIntRing(mo.getVal()); 770 } else { 771 coeff = new ModLongRing(mo.getVal()); 772 } 773 } else { 774 coeff = new ModIntegerRing(mo.getVal()); 775 } 776 //System.out.println("coeff = " + coeff + " :: " + coeff.getClass()); 777 ct = coeffType.ModInt; 778 } else { 779 tok.pushBack(); 780 } 781 } else { 782 tok.pushBack(); 783 } 784 if (tt == ']' && openb) { // optional 785 tt = tok.nextToken(); 786 } 787 } else if (tok.sval.equalsIgnoreCase("RatFunc") || tok.sval.equalsIgnoreCase("ModFunc")) { 788 //logger.error("RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer."); 789 throw new InvalidExpressionException( 790 "RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer."); 791 } else if (tok.sval.equalsIgnoreCase("IntFunc")) { 792 String[] rfv = nextVariableList(); 793 //System.out.println("rfv = " + rfv.length + " " + rfv[0]); 794 int vr = rfv.length; 795 BigRational bi = new BigRational(); 796 TermOrder to = new TermOrder(TermOrder.INVLEX); 797 GenPolynomialRing<BigRational> pcf = new GenPolynomialRing<BigRational>(bi, vr, to, rfv); 798 coeff = pcf; 799 ct = coeffType.IntFunc; 800 } else if (tok.sval.equalsIgnoreCase("AN")) { 801 tt = tok.nextToken(); 802 if (tt == '[') { 803 tt = tok.nextToken(); 804 RingFactory tcfac = new ModIntegerRing("19"); 805 if (tok.sval != null && tok.sval.length() > 0) { 806 if (digit(tok.sval.charAt(0))) { 807 tcfac = new ModIntegerRing(tok.sval); 808 } else { 809 tcfac = new BigRational(); 810 tok.pushBack(); 811 } 812 } else { 813 tcfac = new BigRational(); 814 tok.pushBack(); 815 } 816 String[] anv = nextVariableList(); 817 //System.out.println("anv = " + anv.length + " " + anv[0]); 818 int vs = anv.length; 819 if (vs != 1) { 820 throw new InvalidExpressionException( 821 "AlgebraicNumber only for univariate polynomials " 822 + Arrays.toString(anv)); 823 } 824 String[] ovars = vars; 825 vars = anv; 826 GenPolynomialRing tpfac = pfac; 827 RingFactory tfac = fac; 828 fac = tcfac; 829 // pfac and fac used in nextPolynomial() 830 if (tcfac instanceof ModIntegerRing) { 831 pfac = new GenPolynomialRing<ModInteger>(tcfac, vs, new TermOrder(), anv); 832 } else { 833 pfac = new GenPolynomialRing<BigRational>(tcfac, vs, new TermOrder(), anv); 834 } 835 if (debug) { 836 logger.debug("pfac = " + pfac); 837 } 838 tt = tok.nextToken(); 839 GenPolynomial mod; 840 if (tt == '(') { 841 mod = nextPolynomial(); 842 tt = tok.nextToken(); 843 if (tok.ttype != ')') 844 tok.pushBack(); 845 } else { 846 tok.pushBack(); 847 mod = nextPolynomial(); 848 } 849 if (debug) { 850 logger.debug("mod = " + mod); 851 } 852 pfac = tpfac; 853 fac = tfac; 854 vars = ovars; 855 if (tcfac instanceof ModIntegerRing) { 856 GenPolynomial<ModInteger> gfmod; 857 gfmod = (GenPolynomial<ModInteger>) mod; 858 coeff = new AlgebraicNumberRing<ModInteger>(gfmod); 859 ct = coeffType.ANmod; 860 } else { 861 GenPolynomial<BigRational> anmod; 862 anmod = (GenPolynomial<BigRational>) mod; 863 coeff = new AlgebraicNumberRing<BigRational>(anmod); 864 ct = coeffType.ANrat; 865 } 866 if (debug) { 867 logger.debug("coeff = " + coeff); 868 } 869 tt = tok.nextToken(); 870 if (tt == ']') { 871 //ok, no nextToken(); 872 } else { 873 tok.pushBack(); 874 } 875 } else { 876 tok.pushBack(); 877 } 878 } 879 } 880 if (coeff == null) { 881 tok.pushBack(); 882 coeff = new BigRational(); 883 ct = coeffType.BigRat; 884 } 885 parsedCoeff = ct; 886 return coeff; 887 } 888 889 890 /** 891 * Parsing method for weight list. Syntax: 892 * 893 * <pre> 894 * (w1, w2, w3, ..., wn) 895 * </pre> 896 * 897 * @return the next weight list. 898 * @throws IOException 899 */ 900 public long[] nextWeightList() throws IOException { 901 List<Long> l = new ArrayList<Long>(); 902 long e; 903 char first; 904 int tt; 905 tt = tok.nextToken(); 906 if (tt == '(') { 907 logger.debug("weight list"); 908 tt = tok.nextToken(); 909 while (true) { 910 if (tt == StreamTokenizer.TT_EOF) 911 break; 912 if (tt == ')') 913 break; 914 if (tok.sval != null) { 915 first = tok.sval.charAt(0); 916 if (digit(first)) { 917 e = Long.parseLong(tok.sval); 918 l.add(Long.valueOf(e)); 919 //System.out.println("w: " + e); 920 } 921 } 922 tt = tok.nextToken(); // also comma 923 } 924 } else { 925 tok.pushBack(); 926 } 927 Long[] ol = new Long[1]; 928 ol = l.toArray(ol); 929 long[] w = new long[ol.length]; 930 for (int i = 0; i < w.length; i++) { 931 w[i] = ol[ol.length - i - 1].longValue(); 932 } 933 return w; 934 } 935 936 937 /** 938 * Parsing method for weight array. Syntax: 939 * 940 * <pre> 941 * ( (w11, ...,w1n), ..., (wm1, ..., wmn) ) 942 * </pre> 943 * 944 * @return the next weight array. 945 * @throws IOException 946 */ 947 public long[][] nextWeightArray() throws IOException { 948 List<long[]> l = new ArrayList<long[]>(); 949 long[] e; 950 char first; 951 int tt; 952 tt = tok.nextToken(); 953 if (tt == '(') { 954 logger.debug("weight array"); 955 tt = tok.nextToken(); 956 while (true) { 957 if (tt == StreamTokenizer.TT_EOF) 958 break; 959 if (tt == ')') 960 break; 961 if (tt == '(') { 962 tok.pushBack(); 963 e = nextWeightList(); 964 l.add(e); 965 //System.out.println("wa: " + e); 966 } else if (tok.sval != null) { 967 first = tok.sval.charAt(0); 968 if (digit(first)) { 969 tok.pushBack(); 970 tok.pushBack(); 971 e = nextWeightList(); 972 l.add(e); 973 break; 974 //System.out.println("w: " + e); 975 } 976 } 977 tt = tok.nextToken(); // also comma 978 } 979 } else { 980 tok.pushBack(); 981 } 982 Object[] ol = l.toArray(); 983 long[][] w = new long[ol.length][]; 984 for (int i = 0; i < w.length; i++) { 985 w[i] = (long[]) ol[i]; 986 } 987 return w; 988 } 989 990 991 /** 992 * Parsing method for split index. Syntax: 993 * 994 * <pre> 995 * |i| 996 * </pre> 997 * 998 * @return the next split index. 999 * @throws IOException 1000 */ 1001 public int nextSplitIndex() throws IOException { 1002 int e = -1; // =unknown 1003 int e0 = -1; // =unknown 1004 char first; 1005 int tt; 1006 tt = tok.nextToken(); 1007 if (tt == '|') { 1008 if (debug) { 1009 logger.debug("split index"); 1010 } 1011 tt = tok.nextToken(); 1012 if (tt == StreamTokenizer.TT_EOF) { 1013 return e; 1014 } 1015 if (tok.sval != null) { 1016 first = tok.sval.charAt(0); 1017 if (digit(first)) { 1018 e = Integer.parseInt(tok.sval); 1019 //System.out.println("w: " + i); 1020 } 1021 tt = tok.nextToken(); 1022 if (tt != '|') { 1023 tok.pushBack(); 1024 } 1025 } 1026 } else if (tt == '[') { 1027 if (debug) { 1028 logger.debug("split index"); 1029 } 1030 tt = tok.nextToken(); 1031 if (tt == StreamTokenizer.TT_EOF) { 1032 return e; 1033 } 1034 if (tok.sval != null) { 1035 first = tok.sval.charAt(0); 1036 if (digit(first)) { 1037 e0 = Integer.parseInt(tok.sval); 1038 //System.out.println("w: " + i); 1039 } 1040 tt = tok.nextToken(); 1041 if (tt == ',') { 1042 tt = tok.nextToken(); 1043 if (tt == StreamTokenizer.TT_EOF) { 1044 return e0; 1045 } 1046 if (tok.sval != null) { 1047 first = tok.sval.charAt(0); 1048 if (digit(first)) { 1049 e = Integer.parseInt(tok.sval); 1050 //System.out.println("w: " + i); 1051 } 1052 } 1053 if (tt != ']') { 1054 tok.pushBack(); 1055 } 1056 } 1057 } 1058 } else { 1059 tok.pushBack(); 1060 } 1061 return e; 1062 } 1063 1064 1065 /** 1066 * Parsing method for term order name. Syntax: 1067 * 1068 * <pre> 1069 * L | IL | LEX | G | IG | GRLEX | W(weights) | '|'split index'|' 1070 * </pre> 1071 * 1072 * @return the next term order. 1073 * @throws IOException 1074 */ 1075 public TermOrder nextTermOrder() throws IOException { 1076 int evord = TermOrder.DEFAULT_EVORD; 1077 int tt; 1078 tt = tok.nextToken(); 1079 if (tt == StreamTokenizer.TT_EOF) { /* nop */ 1080 } else if (tt == StreamTokenizer.TT_WORD) { 1081 // System.out.println("TT_WORD: " + tok.sval); 1082 if (tok.sval != null) { 1083 if (tok.sval.equalsIgnoreCase("L")) { 1084 evord = TermOrder.INVLEX; 1085 } else if (tok.sval.equalsIgnoreCase("IL")) { 1086 evord = TermOrder.INVLEX; 1087 } else if (tok.sval.equalsIgnoreCase("INVLEX")) { 1088 evord = TermOrder.INVLEX; 1089 } else if (tok.sval.equalsIgnoreCase("LEX")) { 1090 evord = TermOrder.LEX; 1091 } else if (tok.sval.equalsIgnoreCase("G")) { 1092 evord = TermOrder.IGRLEX; 1093 } else if (tok.sval.equalsIgnoreCase("IG")) { 1094 evord = TermOrder.IGRLEX; 1095 } else if (tok.sval.equalsIgnoreCase("IGRLEX")) { 1096 evord = TermOrder.IGRLEX; 1097 } else if (tok.sval.equalsIgnoreCase("GRLEX")) { 1098 evord = TermOrder.GRLEX; 1099 } else if (tok.sval.equalsIgnoreCase("REVITDG")) { 1100 evord = TermOrder.REVITDG; 1101 } else if (tok.sval.equalsIgnoreCase("REVILEX")) { 1102 evord = TermOrder.REVILEX; 1103 } else if (tok.sval.equalsIgnoreCase("W")) { 1104 long[][] w = nextWeightArray(); 1105 return new TermOrder(w); 1106 } 1107 } 1108 } else { 1109 tok.pushBack(); 1110 } 1111 int s = nextSplitIndex(); 1112 if (s <= 0) { 1113 return new TermOrder(evord); 1114 } 1115 return new TermOrder(evord, evord, nvars, s); 1116 } 1117 1118 1119 /** 1120 * Parsing method for polynomial list. Syntax: 1121 * 1122 * <pre> 1123 * ( p1, p2, p3, ..., pn ) 1124 * </pre> 1125 * 1126 * @return the next polynomial list. 1127 * @throws IOException 1128 */ 1129 public List<GenPolynomial> nextPolynomialList() throws IOException { 1130 GenPolynomial a; 1131 List<GenPolynomial> L = new ArrayList<GenPolynomial>(); 1132 int tt; 1133 tt = tok.nextToken(); 1134 if (tt == StreamTokenizer.TT_EOF) 1135 return L; 1136 if (tt != '(') 1137 return L; 1138 logger.debug("polynomial list"); 1139 while (true) { 1140 tt = tok.nextToken(); 1141 if (tok.ttype == ',') 1142 continue; 1143 if (tt == '(') { 1144 a = nextPolynomial(); 1145 tt = tok.nextToken(); 1146 if (tok.ttype != ')') 1147 tok.pushBack(); 1148 } else { 1149 tok.pushBack(); 1150 a = nextPolynomial(); 1151 } 1152 logger.info("next pol = " + a); 1153 L.add(a); 1154 if (tok.ttype == StreamTokenizer.TT_EOF) 1155 break; 1156 if (tok.ttype == ')') 1157 break; 1158 } 1159 return L; 1160 } 1161 1162 1163 /** 1164 * Parsing method for submodule list. Syntax: 1165 * 1166 * <pre> 1167 * ( ( p11, p12, p13, ..., p1n ), ..., ( pm1, pm2, pm3, ..., pmn ) ) 1168 * </pre> 1169 * 1170 * @return the next list of polynomial lists. 1171 * @throws IOException 1172 */ 1173 public List<List<GenPolynomial>> nextSubModuleList() throws IOException { 1174 List<List<GenPolynomial>> L = new ArrayList<List<GenPolynomial>>(); 1175 int tt; 1176 tt = tok.nextToken(); 1177 if (tt == StreamTokenizer.TT_EOF) 1178 return L; 1179 if (tt != '(') 1180 return L; 1181 logger.debug("module list"); 1182 List<GenPolynomial> v = null; 1183 while (true) { 1184 tt = tok.nextToken(); 1185 if (tok.ttype == ',') 1186 continue; 1187 if (tok.ttype == ')') 1188 break; 1189 if (tok.ttype == StreamTokenizer.TT_EOF) 1190 break; 1191 if (tt == '(') { 1192 tok.pushBack(); 1193 v = nextPolynomialList(); 1194 logger.info("next vect = " + v); 1195 L.add(v); 1196 } 1197 } 1198 return L; 1199 } 1200 1201 1202 /** 1203 * Parsing method for solvable polynomial relation table. Syntax: 1204 * 1205 * <pre> 1206 * ( p_1, p_2, p_3, ..., p_{n+1}, p_{n+2}, p_{n+3} ) 1207 * </pre> 1208 * 1209 * semantics: <code>p_{n+1} * p_{n+2} = p_{n+3}</code>. The next relation 1210 * table is stored into the solvable polynomial factory. 1211 * @throws IOException 1212 */ 1213 @SuppressWarnings("unchecked") 1214 public void nextRelationTable() throws IOException { 1215 if (spfac == null) { 1216 return; 1217 } 1218 RelationTable table = spfac.table; 1219 List<GenPolynomial> rels = null; 1220 GenPolynomial p; 1221 GenSolvablePolynomial sp; 1222 int tt; 1223 tt = tok.nextToken(); 1224 if (debug) { 1225 logger.debug("start relation table: " + tt); 1226 } 1227 if (tok.sval != null) { 1228 if (tok.sval.equalsIgnoreCase("RelationTable")) { 1229 rels = nextPolynomialList(); 1230 } 1231 } 1232 if (rels == null) { 1233 tok.pushBack(); 1234 return; 1235 } 1236 for (Iterator<GenPolynomial> it = rels.iterator(); it.hasNext();) { 1237 p = it.next(); 1238 ExpVector e = p.leadingExpVector(); 1239 if (it.hasNext()) { 1240 p = it.next(); 1241 ExpVector f = p.leadingExpVector(); 1242 if (it.hasNext()) { 1243 p = it.next(); 1244 sp = new GenSolvablePolynomial(spfac, p.val); 1245 table.update(e, f, sp); 1246 } 1247 } 1248 } 1249 if (debug) { 1250 logger.info("table = " + table); 1251 } 1252 return; 1253 } 1254 1255 1256 /** 1257 * Parsing method for polynomial set. Syntax: 1258 * 1259 * <pre> 1260 * coeffRing varList termOrderName polyList 1261 * </pre> 1262 * 1263 * @return the next polynomial set. 1264 * @throws IOException 1265 */ 1266 @SuppressWarnings("unchecked") 1267 public PolynomialList nextPolynomialSet() throws IOException { 1268 //String comments = ""; 1269 //comments += nextComment(); 1270 //if (debug) logger.debug("comment = " + comments); 1271 1272 RingFactory coeff = nextCoefficientRing(); 1273 logger.info("coeff = " + coeff.getClass().getSimpleName()); 1274 1275 vars = nextVariableList(); 1276 logger.info("vars = " + Arrays.toString(vars)); 1277 if (vars != null) { 1278 nvars = vars.length; 1279 } 1280 1281 tord = nextTermOrder(); 1282 logger.info("tord = " + tord); 1283 // check more TOs 1284 1285 initFactory(coeff, parsedCoeff); // global: nvars, tord, vars 1286 List<GenPolynomial> s = null; 1287 s = nextPolynomialList(); 1288 logger.info("s = " + s); 1289 // comments += nextComment(); 1290 return new PolynomialList(pfac, s); 1291 } 1292 1293 1294 /** 1295 * Parsing method for module set. Syntax: 1296 * 1297 * <pre> 1298 * coeffRing varList termOrderName moduleList 1299 * </pre> 1300 * 1301 * @return the next module set. 1302 * @throws IOException 1303 */ 1304 @SuppressWarnings("unchecked") 1305 public ModuleList nextSubModuleSet() throws IOException { 1306 //String comments = ""; 1307 //comments += nextComment(); 1308 //if (debug) logger.debug("comment = " + comments); 1309 1310 RingFactory coeff = nextCoefficientRing(); 1311 logger.info("coeff = " + coeff.getClass().getSimpleName()); 1312 1313 vars = nextVariableList(); 1314 logger.info("vars = " + Arrays.toString(vars)); 1315 if (vars != null) { 1316 nvars = vars.length; 1317 } 1318 1319 tord = nextTermOrder(); 1320 logger.info("tord = " + tord); 1321 // check more TOs 1322 1323 initFactory(coeff, parsedCoeff); // global: nvars, tord, vars 1324 List<List<GenPolynomial>> m = null; 1325 m = nextSubModuleList(); 1326 logger.info("m = " + m); 1327 // comments += nextComment(); 1328 1329 return new ModuleList(pfac, m); 1330 } 1331 1332 1333 /** 1334 * Parsing method for solvable polynomial list. Syntax: 1335 * 1336 * <pre> 1337 * ( p1, p2, p3, ..., pn ) 1338 * </pre> 1339 * 1340 * @return the next solvable polynomial list. 1341 * @throws IOException 1342 */ 1343 @SuppressWarnings("unchecked") 1344 public List<GenSolvablePolynomial> nextSolvablePolynomialList() throws IOException { 1345 List<GenPolynomial> s = nextPolynomialList(); 1346 logger.info("s = " + s); 1347 // comments += nextComment(); 1348 1349 GenPolynomial p; 1350 GenSolvablePolynomial ps; 1351 List<GenSolvablePolynomial> sp = new ArrayList<GenSolvablePolynomial>(s.size()); 1352 for (Iterator<GenPolynomial> it = s.iterator(); it.hasNext();) { 1353 p = it.next(); 1354 ps = new GenSolvablePolynomial(spfac, p.val); 1355 //System.out.println("ps = " + ps); 1356 sp.add(ps); 1357 } 1358 return sp; 1359 } 1360 1361 1362 /** 1363 * Parsing method for solvable polynomial. Syntax: same as for polynomial. 1364 * If the relation table is set-up, then multiplication will mean 1365 * solvable-multiplication. 1366 * @return the next polynomial. 1367 * @throws IOException 1368 */ 1369 @SuppressWarnings("unchecked") 1370 public GenSolvablePolynomial nextSolvablePolynomial() throws IOException { 1371 GenPolynomial p = nextPolynomial(); 1372 logger.info("p = " + p); 1373 // comments += nextComment(); 1374 1375 GenSolvablePolynomial ps = new GenSolvablePolynomial(spfac, p.val); 1376 //System.out.println("ps = " + ps); 1377 return ps; 1378 } 1379 1380 1381 /** 1382 * Parsing method for solvable polynomial set. Syntax: 1383 * 1384 * <pre> 1385 * varList termOrderName relationTable polyList 1386 * </pre> 1387 * 1388 * @return the next solvable polynomial set. 1389 * @throws IOException 1390 */ 1391 @SuppressWarnings("unchecked") 1392 public PolynomialList nextSolvablePolynomialSet() throws IOException { 1393 //String comments = ""; 1394 //comments += nextComment(); 1395 //if (debug) logger.debug("comment = " + comments); 1396 1397 RingFactory coeff = nextCoefficientRing(); 1398 logger.info("coeff = " + coeff.getClass().getSimpleName()); 1399 1400 vars = nextVariableList(); 1401 logger.info("vars = " + Arrays.toString(vars)); 1402 if (vars != null) { 1403 nvars = vars.length; 1404 } 1405 1406 tord = nextTermOrder(); 1407 logger.info("tord = " + tord); 1408 // check more TOs 1409 1410 initFactory(coeff, parsedCoeff); // must be because of symmetric read 1411 initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars 1412 //System.out.println("pfac = " + pfac); 1413 //System.out.println("spfac = " + spfac); 1414 1415 nextRelationTable(); 1416 if (logger.isInfoEnabled()) { 1417 logger.info("table = " + table); 1418 } 1419 1420 List<GenSolvablePolynomial> s = null; 1421 s = nextSolvablePolynomialList(); 1422 logger.info("s = " + s); 1423 // comments += nextComment(); 1424 return new PolynomialList(spfac, s); // Ordered ? 1425 } 1426 1427 1428 /** 1429 * Parsing method for solvable submodule list. Syntax: 1430 * 1431 * <pre> 1432 * ( ( p11, p12, p13, ..., p1n ), ..., ( pm1, pm2, pm3, ..., pmn ) ) 1433 * </pre> 1434 * 1435 * @return the next list of solvable polynomial lists. 1436 * @throws IOException 1437 */ 1438 public List<List<GenSolvablePolynomial>> nextSolvableSubModuleList() throws IOException { 1439 List<List<GenSolvablePolynomial>> L = new ArrayList<List<GenSolvablePolynomial>>(); 1440 int tt; 1441 tt = tok.nextToken(); 1442 if (tt == StreamTokenizer.TT_EOF) 1443 return L; 1444 if (tt != '(') 1445 return L; 1446 logger.debug("module list"); 1447 List<GenSolvablePolynomial> v = null; 1448 while (true) { 1449 tt = tok.nextToken(); 1450 if (tok.ttype == ',') 1451 continue; 1452 if (tok.ttype == ')') 1453 break; 1454 if (tok.ttype == StreamTokenizer.TT_EOF) 1455 break; 1456 if (tt == '(') { 1457 tok.pushBack(); 1458 v = nextSolvablePolynomialList(); 1459 logger.info("next vect = " + v); 1460 L.add(v); 1461 } 1462 } 1463 return L; 1464 } 1465 1466 1467 /** 1468 * Parsing method for solvable module set. Syntax: 1469 * 1470 * <pre> 1471 * varList termOrderName relationTable moduleList 1472 * </pre> 1473 * 1474 * @return the next solvable module set. 1475 * @throws IOException 1476 */ 1477 @SuppressWarnings("unchecked") 1478 public ModuleList nextSolvableSubModuleSet() throws IOException { 1479 //String comments = ""; 1480 //comments += nextComment(); 1481 //if (debug) logger.debug("comment = " + comments); 1482 1483 RingFactory coeff = nextCoefficientRing(); 1484 logger.info("coeff = " + coeff.getClass().getSimpleName()); 1485 1486 vars = nextVariableList(); 1487 logger.info("vars = " + Arrays.toString(vars)); 1488 if (vars != null) { 1489 nvars = vars.length; 1490 } 1491 1492 tord = nextTermOrder(); 1493 logger.info("tord = " + tord); 1494 // check more TOs 1495 1496 initFactory(coeff, parsedCoeff); // must be because of symmetric read 1497 initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars 1498 1499 //System.out.println("spfac = " + spfac); 1500 1501 nextRelationTable(); 1502 if (logger.isInfoEnabled()) { 1503 logger.info("table = " + table); 1504 } 1505 1506 List<List<GenSolvablePolynomial>> s = null; 1507 s = nextSolvableSubModuleList(); 1508 logger.info("s = " + s); 1509 // comments += nextComment(); 1510 1511 return new OrderedModuleList(spfac, s); // Ordered 1512 } 1513 1514 1515 // must also allow +/- // does not work with tokenizer 1516 //private static boolean number(char x) { 1517 // return digit(x) || x == '-' || x == '+'; 1518 //} 1519 1520 1521 static boolean digit(char x) { 1522 return '0' <= x && x <= '9'; 1523 } 1524 1525 1526 static boolean letter(char x) { 1527 return ('a' <= x && x <= 'z') || ('A' <= x && x <= 'Z'); 1528 } 1529 1530 1531 // unused 1532 public void nextComma() throws IOException { 1533 int tt; 1534 if (tok.ttype == ',') { 1535 tt = tok.nextToken(); 1536 if (debug) { 1537 logger.debug("after comma: " + tt); 1538 } 1539 } 1540 } 1541 1542 1543 /** 1544 * Parse variable list from String. 1545 * @param s String. Syntax: 1546 * 1547 * <pre> 1548 * (n1,...,nk) 1549 * </pre> 1550 * 1551 * or 1552 * 1553 * <pre> 1554 * (n1 ... nk) 1555 * </pre> 1556 * 1557 * parenthesis are optional. 1558 * @return array of variable names found in s. 1559 */ 1560 public static String[] variableList(String s) { 1561 String[] vl = null; 1562 if (s == null) { 1563 return vl; 1564 } 1565 String st = s.trim(); 1566 if (st.length() == 0) { 1567 return new String[0]; 1568 } 1569 if (st.charAt(0) == '(') { 1570 st = st.substring(1); 1571 } 1572 if (st.charAt(st.length() - 1) == ')') { 1573 st = st.substring(0, st.length() - 1); 1574 } 1575 st = st.replaceAll(",", " "); 1576 List<String> sl = new ArrayList<String>(); 1577 Scanner sc = new Scanner(st); 1578 while (sc.hasNext()) { 1579 String sn = sc.next(); 1580 sl.add(sn); 1581 } 1582 sc.close(); 1583 vl = new String[sl.size()]; 1584 int i = 0; 1585 for (String si : sl) { 1586 vl[i] = si; 1587 i++; 1588 } 1589 return vl; 1590 } 1591 1592 1593 /** 1594 * Extract variable list from expression. 1595 * @param s String. Syntax: any polynomial expression. 1596 * @return array of variable names found in s. 1597 */ 1598 public static String[] expressionVariables(String s) { 1599 String[] vl = null; 1600 if (s == null) { 1601 return vl; 1602 } 1603 String st = s.trim(); 1604 if (st.length() == 0) { 1605 return new String[0]; 1606 } 1607 st = st.replaceAll(",", " "); 1608 st = st.replaceAll("\\+", " "); 1609 st = st.replaceAll("-", " "); 1610 st = st.replaceAll("\\*", " "); 1611 st = st.replaceAll("/", " "); 1612 st = st.replaceAll("\\(", " "); 1613 st = st.replaceAll("\\)", " "); 1614 st = st.replaceAll("\\{", " "); 1615 st = st.replaceAll("\\}", " "); 1616 st = st.replaceAll("\\[", " "); 1617 st = st.replaceAll("\\]", " "); 1618 st = st.replaceAll("\\^", " "); 1619 //System.out.println("st = " + st); 1620 1621 Set<String> sl = new TreeSet<String>(); 1622 Scanner sc = new Scanner(st); 1623 while (sc.hasNext()) { 1624 String sn = sc.next(); 1625 if (sn == null || sn.length() == 0) { 1626 continue; 1627 } 1628 //System.out.println("sn = " + sn); 1629 int i = 0; 1630 while (digit(sn.charAt(i)) && i < sn.length() - 1) { 1631 i++; 1632 } 1633 //System.out.println("sn = " + sn + ", i = " + i); 1634 if (i > 0) { 1635 sn = sn.substring(i, sn.length()); 1636 } 1637 //System.out.println("sn = " + sn); 1638 if (sn.length() == 0) { 1639 continue; 1640 } 1641 if (!letter(sn.charAt(0))) { 1642 continue; 1643 } 1644 //System.out.println("sn = " + sn); 1645 sl.add(sn); 1646 } 1647 sc.close(); 1648 vl = new String[sl.size()]; 1649 int i = 0; 1650 for (String si : sl) { 1651 vl[i] = si; 1652 i++; 1653 } 1654 return vl; 1655 } 1656 1657}