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