001/* 002 * $Id$ 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.LogManager; 023import org.apache.logging.log4j.Logger; 024 025import edu.jas.arith.BigComplex; 026import edu.jas.arith.BigDecimal; 027import edu.jas.arith.BigInteger; 028import edu.jas.arith.BigOctonion; 029import edu.jas.arith.BigQuaternion; 030import edu.jas.arith.BigQuaternionRing; 031import edu.jas.arith.BigRational; 032import edu.jas.arith.ModIntRing; 033import edu.jas.arith.ModInteger; 034import edu.jas.arith.ModIntegerRing; 035import edu.jas.arith.ModLongRing; 036import edu.jas.structure.Power; 037import edu.jas.structure.MonoidElem; 038import edu.jas.structure.RingElem; 039import edu.jas.structure.RingFactory; 040 041 042/** 043 * GenPolynomial Tokenizer. Used to read rational polynomials and lists of 044 * polynomials from input streams. Arbitrary polynomial rings and coefficient 045 * rings can be read with RingFactoryTokenizer. <b>Note:</b> Can no more read 046 * QuotientRing since end of 2010, revision 3441. Quotient coefficients and 047 * others can still be read if the respective factory is provided via the 048 * constructor. 049 * @see edu.jas.application.RingFactoryTokenizer 050 * @author Heinz Kredel 051 */ 052public class GenPolynomialTokenizer { 053 054 055 private static final Logger logger = LogManager.getLogger(GenPolynomialTokenizer.class); 056 057 058 private static final boolean debug = logger.isDebugEnabled(); 059 060 061 private String[] vars; 062 063 064 private int nvars = 1; 065 066 067 private TermOrder tord; 068 069 070 private RelationTable table; 071 072 073 private final StreamTokenizer tok; 074 075 076 private final Reader reader; 077 078 079 private RingFactory fac; 080 081 082 private static enum coeffType { 083 BigRat, BigInt, ModInt, BigC, BigQ, BigO, BigD, ANrat, ANmod, IntFunc 084 }; 085 086 087 private coeffType parsedCoeff = coeffType.BigRat; 088 089 090 private GenPolynomialRing pfac; 091 092 093 private static enum polyType { 094 PolBigRat, PolBigInt, PolModInt, PolBigC, PolBigD, PolBigQ, PolBigO, PolANrat, PolANmod, PolIntFunc 095 }; 096 097 098 @SuppressWarnings("unused") 099 private polyType parsedPoly = polyType.PolBigRat; 100 101 102 private GenSolvablePolynomialRing spfac; 103 104 105 /** 106 * No-args constructor reads from System.in. 107 */ 108 public GenPolynomialTokenizer() { 109 this(new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF8")))); 110 } 111 112 113 /** 114 * Constructor with Ring and Reader. 115 * @param rf ring factory. 116 * @param r reader stream. 117 */ 118 public GenPolynomialTokenizer(GenPolynomialRing rf, Reader r) { 119 this(r); 120 if (rf == null) { 121 return; 122 } 123 if (rf instanceof GenSolvablePolynomialRing) { 124 pfac = rf; 125 spfac = (GenSolvablePolynomialRing) rf; 126 } else { 127 pfac = rf; 128 spfac = null; 129 } 130 fac = rf.coFac; 131 vars = rf.vars; 132 if (vars != null) { 133 nvars = vars.length; 134 } 135 tord = rf.tord; 136 // relation table 137 if (spfac != null) { 138 table = spfac.table; 139 } else { 140 table = null; 141 } 142 if (!pfac.getZERO().isZERO()) { // happened since May 5 2022 143 // Name : java-11-openjdk-headless 144 // Version : 11.0.15.0 145 // Release : 150000.3.80.1 146 //System.out.println("thread@tokenizer: " + Thread.currentThread()); 147 throw new RuntimeException("zero not 0: " + pfac.getZERO() + " " + pfac.getZERO().val); 148 } 149 } 150 151 152 /** 153 * Constructor with Reader. 154 * @param r reader stream. 155 */ 156 @SuppressWarnings("unchecked") 157 public GenPolynomialTokenizer(Reader r) { 158 vars = null; 159 tord = new TermOrder(); 160 nvars = 1; 161 fac = new BigRational(1); 162 163 pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars); 164 spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars); 165 166 reader = r; 167 tok = new StreamTokenizer(reader); 168 tok.resetSyntax(); 169 // tok.eolIsSignificant(true); no more 170 tok.eolIsSignificant(false); 171 tok.wordChars('0', '9'); 172 tok.wordChars('a', 'z'); 173 tok.wordChars('A', 'Z'); 174 tok.wordChars('_', '_'); // for subscripts x_i 175 tok.wordChars('/', '/'); // wg. rational numbers 176 tok.wordChars('.', '.'); // wg. floats 177 tok.wordChars('~', '~'); // wg. quaternions 178 tok.wordChars(128 + 32, 255); 179 tok.whitespaceChars(0, ' '); 180 tok.commentChar('#'); 181 tok.quoteChar('"'); 182 tok.quoteChar('\''); 183 //tok.slashStarComments(true); does not work 184 185 } 186 187 188 /** 189 * Initialize coefficient and polynomial factories. 190 * @param rf ring factory. 191 * @param ct coefficient type. 192 */ 193 @SuppressWarnings("unchecked") 194 public void initFactory(RingFactory rf, coeffType ct) { 195 fac = rf; 196 parsedCoeff = ct; 197 198 switch (ct) { 199 case BigRat: 200 pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars); 201 parsedPoly = polyType.PolBigRat; 202 break; 203 case BigInt: 204 pfac = new GenPolynomialRing<BigInteger>(fac, nvars, tord, vars); 205 parsedPoly = polyType.PolBigInt; 206 break; 207 case ModInt: 208 pfac = new GenPolynomialRing<ModInteger>(fac, nvars, tord, vars); 209 parsedPoly = polyType.PolModInt; 210 break; 211 case BigC: 212 pfac = new GenPolynomialRing<BigComplex>(fac, nvars, tord, vars); 213 parsedPoly = polyType.PolBigC; 214 break; 215 case BigQ: 216 pfac = new GenPolynomialRing<BigQuaternion>(fac, nvars, tord, vars); 217 parsedPoly = polyType.PolBigQ; 218 break; 219 case BigO: 220 pfac = new GenPolynomialRing<BigOctonion>(fac, nvars, tord, vars); 221 parsedPoly = polyType.PolBigO; 222 break; 223 case BigD: 224 pfac = new GenPolynomialRing<BigDecimal>(fac, nvars, tord, vars); 225 parsedPoly = polyType.PolBigD; 226 break; 227 case IntFunc: 228 pfac = new GenPolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars); 229 parsedPoly = polyType.PolIntFunc; 230 break; 231 default: 232 pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars); 233 parsedPoly = polyType.PolBigRat; 234 } 235 } 236 237 238 /** 239 * Initialize coefficient and solvable polynomial factories. 240 * @param rf ring factory. 241 * @param ct coefficient type. 242 */ 243 @SuppressWarnings("unchecked") 244 public void initSolvableFactory(RingFactory rf, coeffType ct) { 245 fac = rf; 246 parsedCoeff = ct; 247 248 switch (ct) { 249 case BigRat: 250 spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars); 251 parsedPoly = polyType.PolBigRat; 252 break; 253 case BigInt: 254 spfac = new GenSolvablePolynomialRing<BigInteger>(fac, nvars, tord, vars); 255 parsedPoly = polyType.PolBigInt; 256 break; 257 case ModInt: 258 spfac = new GenSolvablePolynomialRing<ModInteger>(fac, nvars, tord, vars); 259 parsedPoly = polyType.PolModInt; 260 break; 261 case BigC: 262 spfac = new GenSolvablePolynomialRing<BigComplex>(fac, nvars, tord, vars); 263 parsedPoly = polyType.PolBigC; 264 break; 265 case BigQ: 266 spfac = new GenSolvablePolynomialRing<BigQuaternion>(fac, nvars, tord, vars); 267 parsedPoly = polyType.PolBigQ; 268 break; 269 case BigO: 270 spfac = new GenSolvablePolynomialRing<BigOctonion>(fac, nvars, tord, vars); 271 parsedPoly = polyType.PolBigO; 272 break; 273 case BigD: 274 spfac = new GenSolvablePolynomialRing<BigDecimal>(fac, nvars, tord, vars); 275 parsedPoly = polyType.PolBigD; 276 break; 277 case IntFunc: 278 spfac = new GenSolvablePolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars); 279 parsedPoly = polyType.PolIntFunc; 280 break; 281 default: 282 spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars); 283 parsedPoly = polyType.PolBigRat; 284 } 285 } 286 287 288 /** 289 * Parsing method for GenPolynomial. Syntax depends also on the syntax of 290 * the coefficients, as the respective parser is used. Basic term/monomial 291 * syntax: 292 * 293 * <pre> 294 ... coefficient variable**exponent ... variable^exponent + ... - .... 295 * </pre> 296 * 297 * Juxtaposition means multiplication <code>*</code>. Then terms/monomials 298 * can be added or subtracted <code>+, -</code> and grouped by parenthesis 299 * <code>()</code>. There are some heuristics to detect when a coefficient 300 * should be parsed. To force parsing of a coefficient enclose it in braces 301 * <code>{}</code>. 302 * @return the next polynomial. 303 * @throws IOException 304 */ 305 @SuppressWarnings("unchecked") 306 public GenPolynomial nextPolynomial() throws IOException { 307 logger.debug("torder = {}", tord); 308 GenPolynomial a = pfac.getZERO(); 309 GenPolynomial a1 = pfac.getONE(); 310 ExpVector leer = pfac.evzero; 311 312 if (debug) { 313 logger.debug("pfac = {}", pfac.toScript()); 314 logger.debug("a = {}", a); 315 logger.debug("a1 = {}", a1); 316 } 317 GenPolynomial b = a1; 318 GenPolynomial c; 319 int tt; //, oldtt; 320 //String rat = ""; 321 char first; 322 RingElem r; 323 ExpVector e; 324 int ix; 325 long ie; 326 while (true) { 327 // next input. determine next action 328 tt = tok.nextToken(); 329 //System.out.println("while tt = " + tok); 330 logger.debug("while tt = {}", tok); 331 if (tt == StreamTokenizer.TT_EOF) 332 break; 333 switch (tt) { 334 case ')': 335 case ',': 336 return a; // do not change or remove 337 case '-': 338 b = b.negate(); 339 case '+': 340 case '*': 341 tt = tok.nextToken(); 342 break; 343 default: // skip 344 } 345 // read coefficient, monic monomial and polynomial 346 if (tt == StreamTokenizer.TT_EOF) 347 break; 348 switch (tt) { 349 // case '_': removed 350 case '}': 351 throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b); 352 case '{': // recursion 353 StringBuffer rf = new StringBuffer(); 354 int level = 0; 355 do { 356 tt = tok.nextToken(); 357 //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level); 358 if (tt == StreamTokenizer.TT_EOF) { 359 throw new InvalidExpressionException( 360 "mismatch of braces after " + a + ", error at " + b); 361 } 362 if (tt == '{') { 363 level++; 364 } 365 if (tt == '}') { 366 level--; 367 if (level < 0) { 368 continue; // skip last closing brace 369 } 370 } 371 if (tok.sval != null) { 372 if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') { 373 rf.append(" "); 374 } 375 rf.append(tok.sval); // " " + 376 } else { 377 rf.append((char) tt); 378 } 379 } while (level >= 0); 380 //System.out.println("coeff{} = " + rf.toString() ); 381 try { 382 r = (RingElem) fac.parse(rf.toString()); 383 } catch (NumberFormatException re) { 384 throw new InvalidExpressionException("not a number :" + rf + ": " + fac, re); 385 } 386 logger.debug("coeff {}", r); 387 ie = nextExponent(); 388 logger.debug("ie {}", ie); 389 r = (RingElem) r.power(ie); 390 logger.debug("coeff^ie {}", r); 391 b = b.multiply(r, leer); 392 393 tt = tok.nextToken(); 394 logger.debug("tt,digit = {}", tok); 395 //no break; 396 break; 397 398 //case '.': // eventually a float 399 //System.out.println("start . = " + reader); 400 //throw new InvalidExpressionException("float must start with a digit "); 401 402 case StreamTokenizer.TT_WORD: 403 //System.out.println("TT_WORD: " + tok.sval); 404 if (tok.sval == null || tok.sval.length() == 0) 405 break; 406 // read coefficient 407 first = tok.sval.charAt(0); 408 if (digit(first) || first == '/' || first == '.' || first == '~') { 409 //System.out.println("coeff 0 = " + tok.sval ); 410 StringBuffer df = new StringBuffer(); 411 df.append(tok.sval); 412 if (tok.sval.length() > 1 && digit(tok.sval.charAt(1))) { 413 //System.out.println("start / or . = " + tok.sval); 414 if (first == '/') { // let x/2 be x 1/2 415 df.insert(0, "1"); 416 } 417 if (first == '.') { // let x.2 be x 0.2 418 df.insert(0, "0"); 419 } 420 } 421 if (tok.sval.charAt(tok.sval.length() - 1) == 'i') { // complex number 422 tt = tok.nextToken(); 423 logger.debug("tt,im = {}", tok); 424 if (tok.sval != null || tt == '-') { 425 if (tok.sval != null) { 426 df.append(tok.sval); 427 } else { 428 df.append("-"); 429 } 430 if (tt == '-') { 431 tt = tok.nextToken(); // todo: decimal number 432 if (tok.sval != null && digit(tok.sval.charAt(0))) { 433 df.append(tok.sval); 434 } else { 435 tok.pushBack(); 436 } 437 } 438 } else { 439 tok.pushBack(); 440 } 441 } 442 if (tok.sval.charAt(tok.sval.length() - 1) == 'j') { // quaternion number 443 tt = tok.nextToken(); 444 logger.debug("tt,jm = {}", tok); 445 if (tok.sval != null || tt == '-') { 446 if (tok.sval != null) { 447 df.append(tok.sval); 448 } else { 449 df.append("-"); 450 } 451 if (tt == '-') { 452 tt = tok.nextToken(); // todo: decimal number 453 if (tok.sval != null && digit(tok.sval.charAt(0))) { 454 df.append(tok.sval); 455 } else { 456 tok.pushBack(); 457 } 458 } 459 } else { 460 tok.pushBack(); 461 } 462 } 463 if (tok.sval.charAt(tok.sval.length() - 1) == 'k') { // quaternion number 464 tt = tok.nextToken(); 465 logger.debug("tt,km = {}", tok); 466 if (tok.sval != null || tt == '-') { 467 if (tok.sval != null) { 468 df.append(tok.sval); 469 } else { 470 df.append("-"); 471 } 472 if (tt == '-') { 473 tt = tok.nextToken(); // todo: decimal number 474 if (tok.sval != null && digit(tok.sval.charAt(0))) { 475 df.append(tok.sval); 476 } else { 477 tok.pushBack(); 478 } 479 } 480 } else { 481 tok.pushBack(); 482 } 483 } 484 tt = tok.nextToken(); 485 if (tt == '.') { // decimal number, obsolete by word char? 486 tt = tok.nextToken(); 487 logger.debug("tt,dot = {}", tok); 488 if (tok.sval != null) { 489 df.append("."); 490 df.append(tok.sval); 491 } else { 492 tok.pushBack(); 493 tok.pushBack(); 494 } 495 } else { 496 tok.pushBack(); 497 } 498 try { 499 //System.out.println("df = " + df + ", fac = " + fac.getClass()); 500 r = (RingElem) fac.parse(df.toString()); 501 //System.out.println("r = " + r); 502 } catch (NumberFormatException re) { 503 //System.out.println("re = " + re); 504 throw new InvalidExpressionException("not a number :" + df + ": " + fac, re); 505 } 506 logger.debug("coeff {}", r); 507 //System.out.println("r = " + r.toScriptFactory()); 508 ie = nextExponent(); 509 logger.debug("ie {}", ie); 510 // r = r^ie; 511 r = (RingElem) r.power(ie); 512 logger.debug("coeff^ie {}", r); 513 b = b.multiply(r, leer); 514 515 tt = tok.nextToken(); 516 logger.debug("tt,digit = {}", tok); 517 } 518 if (tt == StreamTokenizer.TT_EOF) 519 break; 520 if (tok.sval == null) 521 break; 522 // read monomial or recursion 523 first = tok.sval.charAt(0); 524 if (letter(first)) { 525 ix = leer.indexVar(tok.sval, vars); //indexVar( tok.sval ); 526 if (ix < 0) { // not found 527 try { 528 r = (RingElem) fac.parse(tok.sval); 529 } catch (NumberFormatException re) { 530 throw new InvalidExpressionException("recursively unknown variable " + tok.sval); 531 } 532 logger.info("coeff {}", r); 533 //if (r.isONE() || r.isZERO()) { 534 //logger.error("Unknown variable {}", tok.sval); 535 //break; 536 //throw new InvalidExpressionException("recursively unknown variable " + tok.sval); 537 //} 538 ie = nextExponent(); 539 // System.out.println("ie: " + ie); 540 r = (RingElem) r.power(ie); 541 b = b.multiply(r); 542 } else { // found 543 // System.out.println("ix: " + ix); 544 ie = nextExponent(); 545 // System.out.println("ie: " + ie); 546 e = ExpVector.create(vars.length, ix, ie); 547 b = b.multiply(e); 548 } 549 tt = tok.nextToken(); 550 logger.debug("tt,letter = {}", tok); 551 } 552 break; 553 554 case '(': 555 c = nextPolynomial(); 556 logger.debug("factor {}", c); 557 ie = nextExponent(); 558 logger.debug("ie {}", ie); 559 c = (GenPolynomial) c.power(ie); 560 logger.debug("factor^ie {}", c); 561 b = b.multiply(c); 562 563 tt = tok.nextToken(); 564 logger.debug("tt,digit = {}", tok); 565 //no break; 566 break; 567 568 default: //skip 569 } 570 if (tt == StreamTokenizer.TT_EOF) 571 break; 572 // complete polynomial 573 tok.pushBack(); 574 switch (tt) { 575 case '-': 576 case '+': 577 case ')': 578 case ',': 579 logger.debug("b, = {}", b); 580 a = a.sum(b); 581 b = a1; 582 break; 583 case '*': 584 logger.debug("b, = {}", b); 585 //a = a.sum(b); 586 //b = a1; 587 break; 588 case '\n': 589 tt = tok.nextToken(); 590 logger.debug("tt,nl = {}", tt); 591 break; 592 default: // skip or finish ? 593 logger.debug("default: {}", tok); 594 } 595 } 596 logger.debug("b = {}", b); 597 a = a.sum(b); 598 logger.debug("a = {}", a); 599 // b = a1; 600 return a; 601 } 602 603 604 /** 605 * Parsing method for exponent (of variable). Syntax: 606 * <pre> 607 * ^long | **long 608 * </pre> 609 * 610 * @return the next exponent or 1. 611 * @throws IOException 612 */ 613 public long nextExponent() throws IOException { 614 long e = 1; 615 char first; 616 int tt; 617 tt = tok.nextToken(); 618 if (tt == '^') { 619 logger.debug("exponent ^"); 620 tt = tok.nextToken(); 621 if (tok.sval != null) { 622 first = tok.sval.charAt(0); 623 if (digit(first)) { 624 e = Long.parseLong(tok.sval); 625 logger.debug("exponent ^{}", e); 626 return e; 627 } 628 } 629 } 630 if (tt == '*') { 631 tt = tok.nextToken(); 632 if (tt == '*') { 633 logger.debug("exponent **"); 634 tt = tok.nextToken(); 635 if (tok.sval != null) { 636 first = tok.sval.charAt(0); 637 if (digit(first)) { 638 e = Long.parseLong(tok.sval); 639 logger.debug("exponent **{}", e); 640 return e; 641 } 642 } 643 } 644 tok.pushBack(); 645 } 646 tok.pushBack(); 647 return e; 648 } 649 650 651 /** 652 * Parsing method for comments. Syntax: 653 * 654 * <pre> 655 * (* comment *) | /_* comment *_/ 656 * </pre> 657 * 658 * without <code>_</code>. Unused, as it does not work with this pushBack(). 659 */ 660 public String nextComment() throws IOException { 661 // syntax: (* comment *) | /* comment */ 662 StringBuffer c = new StringBuffer(); 663 int tt; 664 logger.debug("comment: {}", tok); 665 tt = tok.nextToken(); 666 logger.debug("comment: {}", tok); 667 if (tt == '(') { 668 tt = tok.nextToken(); 669 logger.debug("comment: {}", tok); 670 if (tt == '*') { 671 logger.debug("comment: "); 672 while (true) { 673 tt = tok.nextToken(); 674 if (tt == '*') { 675 tt = tok.nextToken(); 676 if (tt == ')') { 677 return c.toString(); 678 } 679 tok.pushBack(); 680 } 681 c.append(tok.sval); 682 } 683 } 684 tok.pushBack(); 685 logger.debug("comment: {}", tok); 686 } 687 tok.pushBack(); 688 logger.debug("comment: {}", tok); 689 return c.toString(); 690 } 691 692 693 /** 694 * Parsing method for variable list. Syntax: 695 * 696 * <pre> 697 * (a, b c, de) 698 * </pre> 699 * 700 * gives <code>[ "a", "b", "c", "de" ]</code> 701 * @return the next variable list. 702 * @throws IOException 703 */ 704 public String[] nextVariableList() throws IOException { 705 List<String> l = new ArrayList<String>(); 706 int tt; 707 tt = tok.nextToken(); 708 //System.out.println("vList tok = " + tok); 709 if (tt == '(' || tt == '{') { 710 logger.debug("variable list"); 711 tt = tok.nextToken(); 712 while (true) { 713 if (tt == StreamTokenizer.TT_EOF) 714 break; 715 if (tt == ')' || tt == '}') 716 break; 717 if (tt == StreamTokenizer.TT_WORD) { 718 //System.out.println("TT_WORD: " + tok.sval); 719 l.add(tok.sval); 720 } 721 tt = tok.nextToken(); 722 } 723 } else { 724 tok.pushBack(); 725 } 726 Object[] ol = l.toArray(); 727 String[] v = new String[ol.length]; 728 for (int i = 0; i < v.length; i++) { 729 v[i] = (String) ol[i]; 730 } 731 return v; 732 } 733 734 735 /** 736 * Parsing method for coefficient ring. Syntax: 737 * 738 * <pre> 739 * Rat | Q | Int | Z | Mod modul | Complex | C | D | Quat | AN[ (var) ( poly ) ] | AN[ modul (var) ( poly ) ] | IntFunc (var_list) 740 * </pre> 741 * 742 * @return the next coefficient factory. 743 * @throws IOException 744 */ 745 @SuppressWarnings({ "unchecked", "cast" }) 746 public RingFactory nextCoefficientRing() throws IOException { 747 RingFactory coeff = null; 748 coeffType ct = null; 749 int tt; 750 tt = tok.nextToken(); 751 if (tok.sval != null) { 752 if (tok.sval.equalsIgnoreCase("Q")) { 753 coeff = new BigRational(0); 754 ct = coeffType.BigRat; 755 } else if (tok.sval.equalsIgnoreCase("Rat")) { 756 coeff = new BigRational(0); 757 ct = coeffType.BigRat; 758 } else if (tok.sval.equalsIgnoreCase("D")) { 759 coeff = new BigDecimal(0); 760 ct = coeffType.BigD; 761 } else if (tok.sval.equalsIgnoreCase("Z")) { 762 coeff = new BigInteger(0); 763 ct = coeffType.BigInt; 764 } else if (tok.sval.equalsIgnoreCase("Int")) { 765 coeff = new BigInteger(0); 766 ct = coeffType.BigInt; 767 } else if (tok.sval.equalsIgnoreCase("C")) { 768 coeff = new BigComplex(0); 769 ct = coeffType.BigC; 770 } else if (tok.sval.equalsIgnoreCase("Complex")) { 771 coeff = new BigComplex(0); 772 ct = coeffType.BigC; 773 } else if (tok.sval.equalsIgnoreCase("Quat")) { 774 logger.warn("parse of quaternion coefficients may fail for negative components (use ~ for -)"); 775 coeff = new BigQuaternionRing(); 776 ct = coeffType.BigQ; 777 } else if (tok.sval.equalsIgnoreCase("Oct")) { 778 logger.warn("parse of octonion coefficients may fail for negative components (use ~ for -)"); 779 coeff = new BigOctonion(new BigQuaternionRing()); 780 ct = coeffType.BigO; 781 } else if (tok.sval.equalsIgnoreCase("Mod")) { 782 tt = tok.nextToken(); 783 boolean openb = false; 784 if (tt == '[') { // optional 785 openb = true; 786 tt = tok.nextToken(); 787 } 788 if (tok.sval != null && tok.sval.length() > 0) { 789 if (digit(tok.sval.charAt(0))) { 790 BigInteger mo = new BigInteger(tok.sval); 791 BigInteger lm = new BigInteger(ModLongRing.MAX_LONG); //wrong: Long.MAX_VALUE); 792 if (mo.compareTo(lm) < 0) { 793 if (mo.compareTo(new BigInteger(ModIntRing.MAX_INT)) < 0) { 794 coeff = new ModIntRing(mo.getVal()); 795 } else { 796 coeff = new ModLongRing(mo.getVal()); 797 } 798 } else { 799 coeff = new ModIntegerRing(mo.getVal()); 800 } 801 //System.out.println("coeff = " + coeff + " :: " + coeff.getClass()); 802 ct = coeffType.ModInt; 803 } else { 804 tok.pushBack(); 805 } 806 } else { 807 tok.pushBack(); 808 } 809 if (tt == ']' && openb) { // optional 810 tt = tok.nextToken(); 811 } 812 } else if (tok.sval.equalsIgnoreCase("RatFunc") || tok.sval.equalsIgnoreCase("ModFunc")) { 813 //logger.error("RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer."); 814 throw new InvalidExpressionException( 815 "RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer."); 816 } else if (tok.sval.equalsIgnoreCase("IntFunc")) { 817 String[] rfv = nextVariableList(); 818 //System.out.println("rfv = " + rfv.length + " " + rfv[0]); 819 int vr = rfv.length; 820 BigRational bi = new BigRational(); 821 TermOrder to = new TermOrder(TermOrder.INVLEX); 822 GenPolynomialRing<BigRational> pcf = new GenPolynomialRing<BigRational>(bi, vr, to, rfv); 823 coeff = pcf; 824 ct = coeffType.IntFunc; 825 } else if (tok.sval.equalsIgnoreCase("AN")) { 826 tt = tok.nextToken(); 827 if (tt == '[') { 828 tt = tok.nextToken(); 829 RingFactory tcfac = new ModIntegerRing("19"); 830 if (tok.sval != null && tok.sval.length() > 0) { 831 if (digit(tok.sval.charAt(0))) { 832 tcfac = new ModIntegerRing(tok.sval); 833 } else { 834 tcfac = new BigRational(); 835 tok.pushBack(); 836 } 837 } else { 838 tcfac = new BigRational(); 839 tok.pushBack(); 840 } 841 String[] anv = nextVariableList(); 842 //System.out.println("anv = " + anv.length + " " + anv[0]); 843 int vs = anv.length; 844 if (vs != 1) { 845 throw new InvalidExpressionException( 846 "AlgebraicNumber only for univariate polynomials " 847 + Arrays.toString(anv)); 848 } 849 String[] ovars = vars; 850 vars = anv; 851 GenPolynomialRing tpfac = pfac; 852 RingFactory tfac = fac; 853 fac = tcfac; 854 // pfac and fac used in nextPolynomial() 855 if (tcfac instanceof ModIntegerRing) { 856 pfac = new GenPolynomialRing<ModInteger>(tcfac, vs, new TermOrder(), anv); 857 } else { 858 pfac = new GenPolynomialRing<BigRational>(tcfac, vs, new TermOrder(), anv); 859 } 860 logger.debug("pfac = {}", pfac); 861 tt = tok.nextToken(); 862 GenPolynomial mod; 863 if (tt == '(') { 864 mod = nextPolynomial(); 865 tt = tok.nextToken(); 866 if (tok.ttype != ')') 867 tok.pushBack(); 868 } else { 869 tok.pushBack(); 870 mod = nextPolynomial(); 871 } 872 logger.debug("mod = {}", mod); 873 pfac = tpfac; 874 fac = tfac; 875 vars = ovars; 876 if (tcfac instanceof ModIntegerRing) { 877 GenPolynomial<ModInteger> gfmod; 878 gfmod = (GenPolynomial<ModInteger>) mod; 879 coeff = new AlgebraicNumberRing<ModInteger>(gfmod); 880 ct = coeffType.ANmod; 881 } else { 882 GenPolynomial<BigRational> anmod; 883 anmod = (GenPolynomial<BigRational>) mod; 884 coeff = new AlgebraicNumberRing<BigRational>(anmod); 885 ct = coeffType.ANrat; 886 } 887 logger.debug("coeff = {}", coeff); 888 tt = tok.nextToken(); 889 if (tt == ']') { 890 //ok, no nextToken(); 891 } else { 892 tok.pushBack(); 893 } 894 } else { 895 tok.pushBack(); 896 } 897 } 898 } 899 if (coeff == null) { 900 tok.pushBack(); 901 coeff = new BigRational(); 902 ct = coeffType.BigRat; 903 } 904 parsedCoeff = ct; 905 return coeff; 906 } 907 908 909 /** 910 * Parsing method for weight list. Syntax: 911 * 912 * <pre> 913 * (w1, w2, w3, ..., wn) 914 * </pre> 915 * 916 * @return the next weight list. 917 * @throws IOException 918 */ 919 public long[] nextWeightList() throws IOException { 920 List<Long> l = new ArrayList<Long>(); 921 long e; 922 char first; 923 int tt; 924 tt = tok.nextToken(); 925 if (tt == '(') { 926 logger.debug("weight list"); 927 tt = tok.nextToken(); 928 while (true) { 929 if (tt == StreamTokenizer.TT_EOF) 930 break; 931 if (tt == ')') 932 break; 933 if (tok.sval != null) { 934 first = tok.sval.charAt(0); 935 if (digit(first)) { 936 e = Long.parseLong(tok.sval); 937 l.add(Long.valueOf(e)); 938 //System.out.println("w: " + e); 939 } 940 } 941 tt = tok.nextToken(); // also comma 942 } 943 } else { 944 tok.pushBack(); 945 } 946 Long[] ol = new Long[1]; 947 ol = l.toArray(ol); 948 long[] w = new long[ol.length]; 949 for (int i = 0; i < w.length; i++) { 950 w[i] = ol[ol.length - i - 1].longValue(); 951 } 952 return w; 953 } 954 955 956 /** 957 * Parsing method for weight array. Syntax: 958 * 959 * <pre> 960 * ( (w11, ...,w1n), ..., (wm1, ..., wmn) ) 961 * </pre> 962 * 963 * @return the next weight array. 964 * @throws IOException 965 */ 966 public long[][] nextWeightArray() throws IOException { 967 List<long[]> l = new ArrayList<long[]>(); 968 long[] e; 969 char first; 970 int tt; 971 tt = tok.nextToken(); 972 if (tt == '(') { 973 logger.debug("weight array"); 974 tt = tok.nextToken(); 975 while (true) { 976 if (tt == StreamTokenizer.TT_EOF) 977 break; 978 if (tt == ')') 979 break; 980 if (tt == '(') { 981 tok.pushBack(); 982 e = nextWeightList(); 983 l.add(e); 984 //System.out.println("wa: " + e); 985 } else if (tok.sval != null) { 986 first = tok.sval.charAt(0); 987 if (digit(first)) { 988 tok.pushBack(); 989 tok.pushBack(); 990 e = nextWeightList(); 991 l.add(e); 992 break; 993 //System.out.println("w: " + e); 994 } 995 } 996 tt = tok.nextToken(); // also comma 997 } 998 } else { 999 tok.pushBack(); 1000 } 1001 Object[] ol = l.toArray(); 1002 long[][] w = new long[ol.length][]; 1003 for (int i = 0; i < w.length; i++) { 1004 w[i] = (long[]) ol[i]; 1005 } 1006 return w; 1007 } 1008 1009 1010 /** 1011 * Parsing method for split index. Syntax: 1012 * 1013 * <pre> 1014 * |i| 1015 * </pre> 1016 * 1017 * @return the next split index. 1018 * @throws IOException 1019 */ 1020 public int nextSplitIndex() throws IOException { 1021 int e = -1; // =unknown 1022 int e0 = -1; // =unknown 1023 char first; 1024 int tt; 1025 tt = tok.nextToken(); 1026 if (tt == '|') { 1027 logger.debug("split index"); 1028 tt = tok.nextToken(); 1029 if (tt == StreamTokenizer.TT_EOF) { 1030 return e; 1031 } 1032 if (tok.sval != null) { 1033 first = tok.sval.charAt(0); 1034 if (digit(first)) { 1035 e = Integer.parseInt(tok.sval); 1036 //System.out.println("w: " + i); 1037 } 1038 tt = tok.nextToken(); 1039 if (tt != '|') { 1040 tok.pushBack(); 1041 } 1042 } 1043 } else if (tt == '[') { 1044 logger.debug("split index"); 1045 tt = tok.nextToken(); 1046 if (tt == StreamTokenizer.TT_EOF) { 1047 return e; 1048 } 1049 if (tok.sval != null) { 1050 first = tok.sval.charAt(0); 1051 if (digit(first)) { 1052 e0 = Integer.parseInt(tok.sval); 1053 //System.out.println("w: " + i); 1054 } 1055 tt = tok.nextToken(); 1056 if (tt == ',') { 1057 tt = tok.nextToken(); 1058 if (tt == StreamTokenizer.TT_EOF) { 1059 return e0; 1060 } 1061 if (tok.sval != null) { 1062 first = tok.sval.charAt(0); 1063 if (digit(first)) { 1064 e = Integer.parseInt(tok.sval); 1065 //System.out.println("w: " + i); 1066 } 1067 } 1068 if (tt != ']') { 1069 tok.pushBack(); 1070 } 1071 } 1072 } 1073 } else { 1074 tok.pushBack(); 1075 } 1076 return e; 1077 } 1078 1079 1080 /** 1081 * Parsing method for term order name. Syntax: 1082 * 1083 * <pre> 1084 * L | IL | LEX | G | IG | GRLEX | W(weights) | '|'split index'|' 1085 * </pre> 1086 * 1087 * @return the next term order. 1088 * @throws IOException 1089 */ 1090 public TermOrder nextTermOrder() throws IOException { 1091 int evord = TermOrder.DEFAULT_EVORD; 1092 int tt; 1093 tt = tok.nextToken(); 1094 if (tt == StreamTokenizer.TT_EOF) { /* nop */ 1095 } else if (tt == StreamTokenizer.TT_WORD) { 1096 // System.out.println("TT_WORD: " + tok.sval); 1097 if (tok.sval != null) { 1098 if (tok.sval.equalsIgnoreCase("L")) { 1099 evord = TermOrder.INVLEX; 1100 } else if (tok.sval.equalsIgnoreCase("IL")) { 1101 evord = TermOrder.INVLEX; 1102 } else if (tok.sval.equalsIgnoreCase("INVLEX")) { 1103 evord = TermOrder.INVLEX; 1104 } else if (tok.sval.equalsIgnoreCase("LEX")) { 1105 evord = TermOrder.LEX; 1106 } else if (tok.sval.equalsIgnoreCase("G")) { 1107 evord = TermOrder.IGRLEX; 1108 } else if (tok.sval.equalsIgnoreCase("IG")) { 1109 evord = TermOrder.IGRLEX; 1110 } else if (tok.sval.equalsIgnoreCase("IGRLEX")) { 1111 evord = TermOrder.IGRLEX; 1112 } else if (tok.sval.equalsIgnoreCase("GRLEX")) { 1113 evord = TermOrder.GRLEX; 1114 } else if (tok.sval.equalsIgnoreCase("REVITDG")) { 1115 evord = TermOrder.REVITDG; 1116 } else if (tok.sval.equalsIgnoreCase("REVILEX")) { 1117 evord = TermOrder.REVILEX; 1118 } else if (tok.sval.equalsIgnoreCase("W")) { 1119 long[][] w = nextWeightArray(); 1120 return new TermOrder(w); 1121 } 1122 } 1123 } else { 1124 tok.pushBack(); 1125 } 1126 int s = nextSplitIndex(); 1127 if (s <= 0) { 1128 return new TermOrder(evord); 1129 } 1130 return new TermOrder(evord, evord, nvars, s); 1131 } 1132 1133 1134 /** 1135 * Parsing method for polynomial list. Syntax: 1136 * 1137 * <pre> 1138 * ( p1, p2, p3, ..., pn ) 1139 * </pre> 1140 * 1141 * @return the next polynomial list. 1142 * @throws IOException 1143 */ 1144 public List<GenPolynomial> nextPolynomialList() throws IOException { 1145 GenPolynomial a; 1146 List<GenPolynomial> L = new ArrayList<GenPolynomial>(); 1147 int tt; 1148 tt = tok.nextToken(); 1149 if (tt == StreamTokenizer.TT_EOF) 1150 return L; 1151 if (tt != '(') 1152 return L; 1153 logger.debug("polynomial list"); 1154 while (true) { 1155 tt = tok.nextToken(); 1156 if (tok.ttype == ',') 1157 continue; 1158 if (tt == '(') { 1159 a = nextPolynomial(); 1160 tt = tok.nextToken(); 1161 if (tok.ttype != ')') 1162 tok.pushBack(); 1163 } else { 1164 tok.pushBack(); 1165 a = nextPolynomial(); 1166 } 1167 logger.info("next pol = {}", a); 1168 L.add(a); 1169 if (tok.ttype == StreamTokenizer.TT_EOF) 1170 break; 1171 if (tok.ttype == ')') 1172 break; 1173 } 1174 return L; 1175 } 1176 1177 1178 /** 1179 * Parsing method for submodule list. Syntax: 1180 * 1181 * <pre> 1182 * ( ( p11, p12, p13, ..., p1n ), ..., ( pm1, pm2, pm3, ..., pmn ) ) 1183 * </pre> 1184 * 1185 * @return the next list of polynomial lists. 1186 * @throws IOException 1187 */ 1188 public List<List<GenPolynomial>> nextSubModuleList() throws IOException { 1189 List<List<GenPolynomial>> L = new ArrayList<List<GenPolynomial>>(); 1190 int tt; 1191 tt = tok.nextToken(); 1192 if (tt == StreamTokenizer.TT_EOF) 1193 return L; 1194 if (tt != '(') 1195 return L; 1196 logger.debug("module list"); 1197 List<GenPolynomial> v = null; 1198 while (true) { 1199 tt = tok.nextToken(); 1200 if (tok.ttype == ',') 1201 continue; 1202 if (tok.ttype == ')') 1203 break; 1204 if (tok.ttype == StreamTokenizer.TT_EOF) 1205 break; 1206 if (tt == '(') { 1207 tok.pushBack(); 1208 v = nextPolynomialList(); 1209 logger.info("next vect = {}", v); 1210 L.add(v); 1211 } 1212 } 1213 return L; 1214 } 1215 1216 1217 /** 1218 * Parsing method for solvable polynomial relation table. Syntax: 1219 * 1220 * <pre> 1221 * ( p_1, p_2, p_3, ..., p_{n+1}, p_{n+2}, p_{n+3} ) 1222 * </pre> 1223 * 1224 * semantics: <code>p_{n+1} * p_{n+2} = p_{n+3}</code>. The next relation 1225 * table is stored into the solvable polynomial factory. 1226 * @throws IOException 1227 */ 1228 @SuppressWarnings("unchecked") 1229 public void nextRelationTable() throws IOException { 1230 if (spfac == null) { 1231 return; 1232 } 1233 RelationTable table = spfac.table; 1234 List<GenPolynomial> rels = null; 1235 GenPolynomial p; 1236 GenSolvablePolynomial sp; 1237 int tt; 1238 tt = tok.nextToken(); 1239 logger.debug("start relation table: {}", tt); 1240 if (tok.sval != null) { 1241 if (tok.sval.equalsIgnoreCase("RelationTable")) { 1242 rels = nextPolynomialList(); 1243 } 1244 } 1245 if (rels == null) { 1246 tok.pushBack(); 1247 return; 1248 } 1249 for (Iterator<GenPolynomial> it = rels.iterator(); it.hasNext();) { 1250 p = it.next(); 1251 ExpVector e = p.leadingExpVector(); 1252 if (it.hasNext()) { 1253 p = it.next(); 1254 ExpVector f = p.leadingExpVector(); 1255 if (it.hasNext()) { 1256 p = it.next(); 1257 sp = new GenSolvablePolynomial(spfac, p.val); 1258 table.update(e, f, sp); 1259 } 1260 } 1261 } 1262 logger.info("table = {}", table); 1263 return; 1264 } 1265 1266 1267 /** 1268 * Parsing method for polynomial set. Syntax: 1269 * 1270 * <pre> 1271 * coeffRing varList termOrderName polyList 1272 * </pre> 1273 * 1274 * @return the next polynomial set. 1275 * @throws IOException 1276 */ 1277 @SuppressWarnings("unchecked") 1278 public PolynomialList nextPolynomialSet() throws IOException { 1279 //String comments = ""; 1280 //comments += nextComment(); 1281 //if (debug) logger.debug("comment = {}", comments); 1282 1283 RingFactory coeff = nextCoefficientRing(); 1284 logger.info("coeff = {}", coeff.getClass().getSimpleName()); 1285 1286 vars = nextVariableList(); 1287 logger.info("vars = {}", Arrays.toString(vars)); 1288 if (vars != null) { 1289 nvars = vars.length; 1290 } 1291 1292 tord = nextTermOrder(); 1293 logger.info("tord = {}", tord); 1294 // check more TOs 1295 1296 initFactory(coeff, parsedCoeff); // global: nvars, tord, vars 1297 List<GenPolynomial> s = null; 1298 s = nextPolynomialList(); 1299 logger.info("s = {}", s); 1300 // comments += nextComment(); 1301 return new PolynomialList(pfac, s); 1302 } 1303 1304 1305 /** 1306 * Parsing method for module set. Syntax: 1307 * 1308 * <pre> 1309 * coeffRing varList termOrderName moduleList 1310 * </pre> 1311 * 1312 * @return the next module set. 1313 * @throws IOException 1314 */ 1315 @SuppressWarnings("unchecked") 1316 public ModuleList nextSubModuleSet() throws IOException { 1317 //String comments = ""; 1318 //comments += nextComment(); 1319 //if (debug) logger.debug("comment = {}", comments); 1320 1321 RingFactory coeff = nextCoefficientRing(); 1322 logger.info("coeff = {}", coeff.getClass().getSimpleName()); 1323 1324 vars = nextVariableList(); 1325 logger.info("vars = {}", Arrays.toString(vars)); 1326 if (vars != null) { 1327 nvars = vars.length; 1328 } 1329 1330 tord = nextTermOrder(); 1331 logger.info("tord = {}", tord); 1332 // check more TOs 1333 1334 initFactory(coeff, parsedCoeff); // global: nvars, tord, vars 1335 List<List<GenPolynomial>> m = null; 1336 m = nextSubModuleList(); 1337 logger.info("m = {}", m); 1338 // comments += nextComment(); 1339 1340 return new ModuleList(pfac, m); 1341 } 1342 1343 1344 /** 1345 * Parsing method for solvable polynomial list. Syntax: 1346 * 1347 * <pre> 1348 * ( p1, p2, p3, ..., pn ) 1349 * </pre> 1350 * 1351 * @return the next solvable polynomial list. 1352 * @throws IOException 1353 */ 1354 @SuppressWarnings("unchecked") 1355 public List<GenSolvablePolynomial> nextSolvablePolynomialList() throws IOException { 1356 List<GenPolynomial> s = nextPolynomialList(); 1357 logger.info("s = {}", s); 1358 // comments += nextComment(); 1359 1360 GenPolynomial p; 1361 GenSolvablePolynomial ps; 1362 List<GenSolvablePolynomial> sp = new ArrayList<GenSolvablePolynomial>(s.size()); 1363 for (Iterator<GenPolynomial> it = s.iterator(); it.hasNext();) { 1364 p = it.next(); 1365 ps = new GenSolvablePolynomial(spfac, p.val); 1366 //System.out.println("ps = " + ps); 1367 sp.add(ps); 1368 } 1369 return sp; 1370 } 1371 1372 1373 /** 1374 * Parsing method for solvable polynomial. Syntax: same as for polynomial. 1375 * If the relation table is set-up, then multiplication will mean 1376 * solvable-multiplication. 1377 * @return the next polynomial. 1378 * @throws IOException 1379 */ 1380 @SuppressWarnings("unchecked") 1381 public GenSolvablePolynomial nextSolvablePolynomial() throws IOException { 1382 GenPolynomial p = nextPolynomial(); 1383 //logger.info("nextPolynomial = {}", p); 1384 // comments += nextComment(); 1385 1386 GenSolvablePolynomial ps = new GenSolvablePolynomial(spfac, p.val); 1387 logger.info("nextSolvablePolynomial = {}", ps); 1388 return ps; 1389 } 1390 1391 1392 /** 1393 * Parsing method for solvable polynomial set. Syntax: 1394 * 1395 * <pre> 1396 * varList termOrderName relationTable polyList 1397 * </pre> 1398 * 1399 * @return the next solvable polynomial set. 1400 * @throws IOException 1401 */ 1402 @SuppressWarnings("unchecked") 1403 public PolynomialList nextSolvablePolynomialSet() throws IOException { 1404 //String comments = ""; 1405 //comments += nextComment(); 1406 //if (debug) logger.debug("comment = {}", comments); 1407 1408 RingFactory coeff = nextCoefficientRing(); 1409 logger.info("coeff = {}", coeff.getClass().getSimpleName()); 1410 1411 vars = nextVariableList(); 1412 logger.info("vars = {}", Arrays.toString(vars)); 1413 if (vars != null) { 1414 nvars = vars.length; 1415 } 1416 1417 tord = nextTermOrder(); 1418 logger.info("tord = {}", tord); 1419 // check more TOs 1420 1421 initFactory(coeff, parsedCoeff); // must be because of symmetric read 1422 initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars 1423 //System.out.println("pfac = " + pfac); 1424 //System.out.println("spfac = " + spfac); 1425 1426 nextRelationTable(); 1427 logger.info("table = {}", table); 1428 1429 List<GenSolvablePolynomial> s = null; 1430 s = nextSolvablePolynomialList(); 1431 logger.info("s = {}", s); 1432 // comments += nextComment(); 1433 return new PolynomialList(spfac, s); // Ordered ? 1434 } 1435 1436 1437 /** 1438 * Parsing method for solvable submodule list. Syntax: 1439 * 1440 * <pre> 1441 * ( ( p11, p12, p13, ..., p1n ), ..., ( pm1, pm2, pm3, ..., pmn ) ) 1442 * </pre> 1443 * 1444 * @return the next list of solvable polynomial lists. 1445 * @throws IOException 1446 */ 1447 public List<List<GenSolvablePolynomial>> nextSolvableSubModuleList() throws IOException { 1448 List<List<GenSolvablePolynomial>> L = new ArrayList<List<GenSolvablePolynomial>>(); 1449 int tt; 1450 tt = tok.nextToken(); 1451 if (tt == StreamTokenizer.TT_EOF) 1452 return L; 1453 if (tt != '(') 1454 return L; 1455 logger.debug("module list"); 1456 List<GenSolvablePolynomial> v = null; 1457 while (true) { 1458 tt = tok.nextToken(); 1459 if (tok.ttype == ',') 1460 continue; 1461 if (tok.ttype == ')') 1462 break; 1463 if (tok.ttype == StreamTokenizer.TT_EOF) 1464 break; 1465 if (tt == '(') { 1466 tok.pushBack(); 1467 v = nextSolvablePolynomialList(); 1468 logger.info("next vect = {}", v); 1469 L.add(v); 1470 } 1471 } 1472 return L; 1473 } 1474 1475 1476 /** 1477 * Parsing method for solvable module set. Syntax: 1478 * 1479 * <pre> 1480 * varList termOrderName relationTable moduleList 1481 * </pre> 1482 * 1483 * @return the next solvable module set. 1484 * @throws IOException 1485 */ 1486 @SuppressWarnings("unchecked") 1487 public ModuleList nextSolvableSubModuleSet() throws IOException { 1488 //String comments = ""; 1489 //comments += nextComment(); 1490 //if (debug) logger.debug("comment = {}", comments); 1491 1492 RingFactory coeff = nextCoefficientRing(); 1493 logger.info("coeff = {}", coeff.getClass().getSimpleName()); 1494 1495 vars = nextVariableList(); 1496 logger.info("vars = {}", Arrays.toString(vars)); 1497 if (vars != null) { 1498 nvars = vars.length; 1499 } 1500 1501 tord = nextTermOrder(); 1502 logger.info("tord = {}", tord); 1503 // check more TOs 1504 1505 initFactory(coeff, parsedCoeff); // must be because of symmetric read 1506 initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars 1507 1508 //System.out.println("spfac = " + spfac); 1509 1510 nextRelationTable(); 1511 logger.info("table = {}", table); 1512 1513 List<List<GenSolvablePolynomial>> s = null; 1514 s = nextSolvableSubModuleList(); 1515 logger.info("s = {}", s); 1516 // comments += nextComment(); 1517 1518 return new OrderedModuleList(spfac, s); // Ordered 1519 } 1520 1521 1522 /** 1523 * Parsing method for word polynomial. Syntax: same as for polynomial. 1524 * Multiplication will be non commutative. 1525 * @return the next polynomial. 1526 * @throws IOException 1527 */ 1528 @SuppressWarnings("unchecked") 1529 public GenWordPolynomial nextWordPolynomial() throws IOException { 1530 GenWordPolynomialRing wfac = new GenWordPolynomialRing(pfac); 1531 return nextWordPolynomial(wfac); 1532 } 1533 1534 1535 /** 1536 * Parsing method for word polynomial. Syntax: same as for polynomial. 1537 * Multiplication will be non commutative. 1538 * @param wfac word polynomial ring. 1539 * @return the next polynomial. 1540 * @throws IOException 1541 */ 1542 @SuppressWarnings("unchecked") 1543 public GenWordPolynomial nextWordPolynomial(GenWordPolynomialRing wfac) throws IOException { 1544 //logger.info("wfac = {}", wfac); 1545 WordFactory wf = wfac.alphabet; 1546 1547 GenWordPolynomial a = wfac.getZERO(); 1548 GenWordPolynomial a1 = wfac.getONE(); 1549 Word leer = wfac.wone; 1550 RingFactory fac = wfac.coFac; 1551 if (debug) { 1552 logger.debug("a = {}", a); 1553 logger.debug("a1 = {}", a1); 1554 } 1555 GenWordPolynomial b = a1; 1556 GenWordPolynomial c; 1557 int tt; 1558 char first; 1559 RingElem r; 1560 Word e; 1561 //int ix; 1562 long ie; 1563 while (true) { 1564 // next input. determine next action 1565 tt = tok.nextToken(); 1566 //System.out.println("while tt = " + tok); 1567 logger.debug("while tt = {}", tok); 1568 if (tt == StreamTokenizer.TT_EOF) 1569 break; 1570 switch (tt) { 1571 case ')': 1572 case ',': 1573 logger.info("nextWordPolynomial = {}", a); 1574 return a; // do not change or remove 1575 case '-': 1576 b = b.negate(); 1577 case '+': 1578 case '*': 1579 tt = tok.nextToken(); 1580 break; 1581 default: // skip 1582 } 1583 // read coefficient, monic monomial and polynomial 1584 if (tt == StreamTokenizer.TT_EOF) 1585 break; 1586 switch (tt) { 1587 // case '_': removed 1588 case '}': 1589 throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b); 1590 case '{': // recursion 1591 StringBuffer rf = new StringBuffer(); 1592 int level = 0; 1593 do { 1594 tt = tok.nextToken(); 1595 //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level); 1596 if (tt == StreamTokenizer.TT_EOF) { 1597 throw new InvalidExpressionException( 1598 "mismatch of braces after " + a + ", error at " + b); 1599 } 1600 if (tt == '{') { 1601 level++; 1602 } 1603 if (tt == '}') { 1604 level--; 1605 if (level < 0) { 1606 continue; // skip last closing brace 1607 } 1608 } 1609 if (tok.sval != null) { 1610 if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') { 1611 rf.append(" "); 1612 } 1613 rf.append(tok.sval); // " " + 1614 } else { 1615 rf.append((char) tt); 1616 } 1617 } while (level >= 0); 1618 //System.out.println("coeff{} = " + rf.toString() ); 1619 try { 1620 r = (RingElem) fac.parse(rf.toString()); 1621 } catch (NumberFormatException re) { 1622 throw new InvalidExpressionException("not a number :" + rf + ": " + fac, re); 1623 } 1624 logger.debug("coeff {}", r); 1625 ie = nextExponent(); 1626 logger.debug("ie {}", ie); 1627 r = (RingElem) r.power(ie); 1628 logger.debug("coeff^ie {}", r); 1629 b = b.multiply(r, leer); 1630 1631 tt = tok.nextToken(); 1632 logger.debug("tt,digit = {}", tok); 1633 //no break; 1634 break; 1635 1636 //case '.': // eventually a float 1637 //System.out.println("start . = " + reader); 1638 //throw new InvalidExpressionException("float must start with a digit "); 1639 1640 case StreamTokenizer.TT_WORD: 1641 //System.out.println("TT_WORD: " + tok.sval); 1642 if (tok.sval == null || tok.sval.length() == 0) 1643 break; 1644 // read coefficient 1645 first = tok.sval.charAt(0); 1646 if (digit(first) || first == '/' || first == '.' || first == '~') { 1647 //System.out.println("coeff 0 = " + tok.sval ); 1648 StringBuffer df = new StringBuffer(); 1649 df.append(tok.sval); 1650 if (tok.sval.length() > 1 && digit(tok.sval.charAt(1))) { 1651 //System.out.println("start / or . = " + tok.sval); 1652 if (first == '/') { // let x/2 be x 1/2 1653 df.insert(0, "1"); 1654 } 1655 if (first == '.') { // let x.2 be x 0.2 1656 df.insert(0, "0"); 1657 } 1658 } 1659 if (tok.sval.charAt(tok.sval.length() - 1) == 'i') { // complex number 1660 tt = tok.nextToken(); 1661 logger.debug("tt,im = {}", tok); 1662 if (tok.sval != null || tt == '-') { 1663 if (tok.sval != null) { 1664 df.append(tok.sval); 1665 } else { 1666 df.append("-"); 1667 } 1668 if (tt == '-') { 1669 tt = tok.nextToken(); // todo: decimal number 1670 if (tok.sval != null && digit(tok.sval.charAt(0))) { 1671 df.append(tok.sval); 1672 1673 } else { 1674 tok.pushBack(); 1675 } 1676 } 1677 } else { 1678 tok.pushBack(); 1679 } 1680 } 1681 tt = tok.nextToken(); 1682 if (tt == '.') { // decimal number, obsolete by word char? 1683 tt = tok.nextToken(); 1684 logger.debug("tt,dot = {}", tok); 1685 if (tok.sval != null) { 1686 df.append("."); 1687 df.append(tok.sval); 1688 } else { 1689 tok.pushBack(); 1690 tok.pushBack(); 1691 } 1692 } else { 1693 tok.pushBack(); 1694 } 1695 try { 1696 //System.out.println("df = " + df + ", fac = " + fac.getClass()); 1697 r = (RingElem) fac.parse(df.toString()); 1698 //System.out.println("r = " + r); 1699 } catch (NumberFormatException re) { 1700 //System.out.println("re = " + re); 1701 throw new InvalidExpressionException("not a number :" + df + ": " + fac, re); 1702 } 1703 logger.debug("coeff {}", r); 1704 //System.out.println("r = " + r.toScriptFactory()); 1705 ie = nextExponent(); 1706 logger.debug("ie {}", ie); 1707 // r = r^ie; 1708 r = (RingElem) r.power(ie); 1709 logger.debug("coeff^ie {}", r); 1710 b = b.multiply(r, leer); 1711 1712 tt = tok.nextToken(); 1713 logger.debug("tt,digit = {}", tok); 1714 } 1715 if (tt == StreamTokenizer.TT_EOF) 1716 break; 1717 if (tok.sval == null) 1718 break; 1719 // read monomial or recursion 1720 first = tok.sval.charAt(0); 1721 if (letter(first)) { 1722 //ix = leer.indexVar(tok.sval, vars); 1723 try { 1724 e = wf.parse(tok.sval); 1725 } catch (IllegalArgumentException ee) { 1726 e = null; 1727 } 1728 logger.info("monom {}", e); 1729 if (e == null) { // not found, look for coeff var 1730 try { 1731 r = (RingElem) fac.parse(tok.sval); 1732 } catch (NumberFormatException re) { 1733 throw new InvalidExpressionException("recursively unknown variable " + tok.sval); 1734 } 1735 ie = nextExponent(); 1736 // System.out.println("ie: " + ie); 1737 r = (RingElem) r.power(ie); 1738 // System.out.println("re: " + r); 1739 b = b.multiply(r, leer); 1740 } else { // found 1741 ie = nextExponent(); 1742 // System.out.println("ie: " + ie); 1743 e = e.power(ie); 1744 // System.out.println("e: " + e); 1745 b = b.multiply(e); 1746 } 1747 tt = tok.nextToken(); 1748 logger.debug("tt,letter = {}", tok); 1749 } 1750 break; 1751 1752 case '(': 1753 c = nextWordPolynomial(wfac); 1754 logger.debug("factor {}", c); 1755 ie = nextExponent(); 1756 logger.debug("ie {}", ie); 1757 c = (GenWordPolynomial) c.power(ie); 1758 logger.debug("factor^ie {}", c); 1759 b = b.multiply(c); 1760 1761 tt = tok.nextToken(); 1762 logger.debug("tt,digit = {}", tok); 1763 //no break; 1764 break; 1765 1766 default: //skip 1767 } 1768 if (tt == StreamTokenizer.TT_EOF) 1769 break; 1770 // complete polynomial 1771 tok.pushBack(); 1772 switch (tt) { 1773 case '-': 1774 case '+': 1775 case ')': 1776 case ',': 1777 logger.debug("b, = {}", b); 1778 a = a.sum(b); 1779 b = a1; 1780 break; 1781 case '*': 1782 logger.debug("b, = {}", b); 1783 //a = a.sum(b); 1784 //b = a1; 1785 break; 1786 case '\n': 1787 tt = tok.nextToken(); 1788 logger.debug("tt,nl = {}", tt); 1789 break; 1790 default: // skip or finish ? 1791 logger.debug("default: {}", tok); 1792 } 1793 } 1794 logger.debug("b = {}", b); 1795 a = a.sum(b); 1796 logger.info("nextWordPolynomial = {}", a); 1797 // b = a1; 1798 return a; 1799 } 1800 1801 1802 /** 1803 * Parsing method for word polynomial list. Syntax: 1804 * 1805 * <pre> 1806 * ( p1, p2, p3, ..., pn ) 1807 * </pre> 1808 * 1809 * @return the next word polynomial list. 1810 * @throws IOException 1811 */ 1812 @SuppressWarnings("unchecked") 1813 public List<GenWordPolynomial> nextWordPolynomialList() throws IOException { 1814 GenWordPolynomialRing wfac = new GenWordPolynomialRing(pfac); 1815 return nextWordPolynomialList(wfac); 1816 } 1817 1818 1819 /** 1820 * Parsing method for word polynomial list. Syntax: 1821 * 1822 * <pre> 1823 * ( p1, p2, p3, ..., pn ) 1824 * </pre> 1825 * 1826 * @param wfac word polynomial ring. 1827 * @return the next word polynomial list. 1828 * @throws IOException 1829 */ 1830 public List<GenWordPolynomial> nextWordPolynomialList(GenWordPolynomialRing wfac) throws IOException { 1831 GenWordPolynomial a; 1832 List<GenWordPolynomial> L = new ArrayList<GenWordPolynomial>(); 1833 int tt; 1834 tt = tok.nextToken(); 1835 if (tt == StreamTokenizer.TT_EOF) 1836 return L; 1837 if (tt != '(') 1838 return L; 1839 logger.debug("word polynomial list"); 1840 while (true) { 1841 tt = tok.nextToken(); 1842 if (tok.ttype == ',') 1843 continue; 1844 if (tt == '(') { 1845 a = nextWordPolynomial(wfac); 1846 tt = tok.nextToken(); 1847 if (tok.ttype != ')') 1848 tok.pushBack(); 1849 } else { 1850 tok.pushBack(); 1851 a = nextWordPolynomial(wfac); 1852 } 1853 logger.info("next pol = {}", a); 1854 L.add(a); 1855 if (tok.ttype == StreamTokenizer.TT_EOF) 1856 break; 1857 if (tok.ttype == ')') 1858 break; 1859 } 1860 return L; 1861 } 1862 1863 1864 /** 1865 * Parsing method for exterior polynomial. Syntax: same as for polynomial. 1866 * Multiplication will be non commutative. 1867 * @return the next polynomial. 1868 * @throws IOException 1869 */ 1870 @SuppressWarnings("unchecked") 1871 public GenExteriorPolynomial nextExteriorPolynomial() throws IOException { 1872 GenExteriorPolynomialRing wfac = new GenExteriorPolynomialRing(pfac); 1873 return nextExteriorPolynomial(wfac); 1874 } 1875 1876 1877 /** 1878 * Parsing method for exterior polynomial. Syntax: except for 1879 * index list same as for polynomial. Multiplication will be 1880 * anti-commutative. 1881 * @param wfac exterior polynomial ring. 1882 * @return the next polynomial. 1883 * @throws IOException 1884 */ 1885 @SuppressWarnings("unchecked") 1886 public GenExteriorPolynomial nextExteriorPolynomial(GenExteriorPolynomialRing wfac) throws IOException { 1887 logger.info("wfac = {}", wfac); 1888 IndexFactory wf = wfac.ixfac; 1889 1890 GenExteriorPolynomial a = wfac.getZERO(); 1891 GenExteriorPolynomial a1 = wfac.getONE(); 1892 IndexList leer = wfac.wone; 1893 RingFactory fac = wfac.coFac; 1894 if (debug) { 1895 logger.debug("a = {}", a); 1896 logger.debug("a1 = {}", a1); 1897 } 1898 GenExteriorPolynomial b = a1; 1899 GenExteriorPolynomial c; 1900 int tt; 1901 char first; 1902 RingElem r; 1903 IndexList e; 1904 //int ix; 1905 long ie; 1906 while (true) { 1907 // next input. determine next action 1908 tt = tok.nextToken(); 1909 //System.out.println("while tt = " + tok); 1910 logger.debug("while tt = {}", tok); 1911 if (tt == StreamTokenizer.TT_EOF) 1912 break; 1913 switch (tt) { 1914 case ')': 1915 case ',': 1916 logger.info("nextExteriorPolynomial = {}", a); 1917 return a; // do not change or remove 1918 case '-': 1919 b = b.negate(); 1920 case '+': 1921 case '*': 1922 tt = tok.nextToken(); 1923 break; 1924 default: // skip 1925 } 1926 // read coefficient, monic monomial and polynomial 1927 if (tt == StreamTokenizer.TT_EOF) 1928 break; 1929 switch (tt) { 1930 // case '_': removed 1931 case '}': 1932 throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b); 1933 case '{': // recursion 1934 StringBuffer rf = new StringBuffer(); 1935 int level = 0; 1936 do { 1937 tt = tok.nextToken(); 1938 //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level); 1939 if (tt == StreamTokenizer.TT_EOF) { 1940 throw new InvalidExpressionException( 1941 "mismatch of braces after " + a + ", error at " + b); 1942 } 1943 if (tt == '{') { 1944 level++; 1945 } 1946 if (tt == '}') { 1947 level--; 1948 if (level < 0) { 1949 continue; // skip last closing brace 1950 } 1951 } 1952 if (tok.sval != null) { 1953 if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') { 1954 rf.append(" "); 1955 } 1956 rf.append(tok.sval); // " " + 1957 } else { 1958 rf.append((char) tt); 1959 } 1960 } while (level >= 0); 1961 //System.out.println("coeff{} = " + rf.toString() ); 1962 try { 1963 r = (RingElem) fac.parse(rf.toString()); 1964 } catch (NumberFormatException re) { 1965 throw new InvalidExpressionException("not a number :" + rf + ": " + fac, re); 1966 } 1967 logger.debug("coeff {}", r); 1968 ie = nextExponent(); 1969 logger.debug("ie {}", ie); 1970 r = (RingElem) r.power(ie); 1971 logger.debug("coeff^ie {}", r); 1972 b = b.multiply(r, leer); 1973 1974 tt = tok.nextToken(); 1975 logger.debug("tt,digit = {}", tok); 1976 //no break; 1977 break; 1978 1979 //case '.': // eventually a float 1980 //System.out.println("start . = " + reader); 1981 //throw new InvalidExpressionException("float must start with a digit "); 1982 1983 case StreamTokenizer.TT_WORD: 1984 //System.out.println("TT_WORD: " + tok.sval); 1985 if (tok.sval == null || tok.sval.length() == 0) 1986 break; 1987 // read coefficient 1988 first = tok.sval.charAt(0); 1989 if (digit(first) || first == '/' || first == '.' || first == '~') { 1990 //System.out.println("coeff 0 = " + tok.sval ); 1991 StringBuffer df = new StringBuffer(); 1992 df.append(tok.sval); 1993 if (tok.sval.length() > 1 && digit(tok.sval.charAt(1))) { 1994 //System.out.println("start / or . = " + tok.sval); 1995 if (first == '/') { // let x/2 be x 1/2 1996 df.insert(0, "1"); 1997 } 1998 if (first == '.') { // let x.2 be x 0.2 1999 df.insert(0, "0"); 2000 } 2001 } 2002 if (tok.sval.charAt(tok.sval.length() - 1) == 'i') { // complex number 2003 tt = tok.nextToken(); 2004 logger.debug("tt,im = {}", tok); 2005 if (tok.sval != null || tt == '-') { 2006 if (tok.sval != null) { 2007 df.append(tok.sval); 2008 } else { 2009 df.append("-"); 2010 } 2011 if (tt == '-') { 2012 tt = tok.nextToken(); // todo: decimal number 2013 if (tok.sval != null && digit(tok.sval.charAt(0))) { 2014 df.append(tok.sval); 2015 2016 } else { 2017 tok.pushBack(); 2018 } 2019 } 2020 } else { 2021 tok.pushBack(); 2022 } 2023 } 2024 tt = tok.nextToken(); 2025 if (tt == '.') { // decimal number, obsolete by word char? 2026 tt = tok.nextToken(); 2027 logger.debug("tt,dot = {}", tok); 2028 if (tok.sval != null) { 2029 df.append("."); 2030 df.append(tok.sval); 2031 } else { 2032 tok.pushBack(); 2033 tok.pushBack(); 2034 } 2035 } else { 2036 tok.pushBack(); 2037 } 2038 try { 2039 //System.out.println("df = " + df + ", fac = " + fac.getClass()); 2040 r = (RingElem) fac.parse(df.toString()); 2041 //System.out.println("r = " + r); 2042 } catch (NumberFormatException re) { 2043 //System.out.println("re = " + re); 2044 throw new InvalidExpressionException("not a number :" + df + ": " + fac, re); 2045 } 2046 logger.debug("coeff {}", r); 2047 //System.out.println("r = " + r.toScriptFactory()); 2048 ie = nextExponent(); 2049 logger.debug("ie {}", ie); 2050 // r = r^ie; 2051 r = (RingElem) r.power(ie); 2052 logger.debug("coeff^ie {}", r); 2053 b = b.multiply(r, leer); 2054 2055 tt = tok.nextToken(); 2056 logger.debug("tt,digit = {}", tok); 2057 } 2058 if (tt == StreamTokenizer.TT_EOF) 2059 break; 2060 if (tok.sval == null) 2061 break; 2062 // read monomial, index list or recursion 2063 first = tok.sval.charAt(0); 2064 //System.out.println("first = '" + first + "'"); 2065 if (letter(first)) { 2066 //ix = leer.indexVar(tok.sval, vars); 2067 if ("E".charAt(0) == first) { 2068 StringBuffer ri = new StringBuffer(); 2069 ri.append(tok.sval); 2070 //System.out.println("index tok.sval " + tok.sval); 2071 while (true) { 2072 tt = tok.nextToken(); 2073 //System.out.println("index tok.token " + tt + ", tok.sval " + tok.sval); 2074 if (tt == '(') { 2075 ri.append("("); 2076 continue; 2077 } 2078 if (tt == ',') { 2079 ri.append(","); 2080 continue; 2081 } 2082 if (tok.sval != null) { 2083 ri.append(tok.sval); 2084 //System.out.println("index tok.sval " + tok.sval); 2085 } 2086 if (tt == ')') { 2087 ri.append(")"); 2088 break; 2089 } 2090 } 2091 //System.out.println("index list, ri " + ri.toString()); 2092 try { 2093 e = wf.parse(ri.toString()); 2094 } catch (IllegalArgumentException ee) { 2095 e = null; 2096 } 2097 } else { 2098 e = null; //wf.valueOf(tok.sval); 2099 } 2100 logger.info("monom {}", e); 2101 //System.out.println("index list, e " + e); 2102 if (e == null) { // not found, look for coeff var 2103 try { 2104 r = (RingElem) fac.parse(tok.sval); 2105 } catch (NumberFormatException re) { 2106 throw new InvalidExpressionException("recursively unknown variable " + tok.sval); 2107 } 2108 ie = nextExponent(); 2109 // System.out.println("ie: " + ie); 2110 r = (RingElem) r.power(ie); 2111 // System.out.println("re: " + r); 2112 b = b.multiply(r, leer); 2113 } else { // found 2114 ie = nextExponent(); 2115 // System.out.println("ie: " + ie); 2116 //no RingElem: e = e.power(ie); 2117 //no RingElem: e = Power.<IndexList> positivePower(e, ie); 2118 if (ie > 1) { // exterior product is 0 2119 e = wf.getZERO(); 2120 } if (ie <= 0) { 2121 e = wf.getONE(); 2122 } 2123 //System.out.println("e: " + e); 2124 b = b.multiply(e); 2125 } 2126 tt = tok.nextToken(); 2127 logger.debug("tt,letter = {}", tok); 2128 } 2129 break; 2130 2131 case '(': 2132 c = nextExteriorPolynomial(wfac); 2133 logger.debug("factor {}", c); 2134 ie = nextExponent(); 2135 logger.debug("ie {}", ie); 2136 c = (GenExteriorPolynomial) c.power(ie); 2137 logger.debug("factor^ie {}", c); 2138 b = b.multiply(c); 2139 2140 tt = tok.nextToken(); 2141 logger.debug("tt,digit = {}", tok); 2142 //no break; 2143 break; 2144 2145 default: //skip 2146 } 2147 if (tt == StreamTokenizer.TT_EOF) 2148 break; 2149 // complete polynomial 2150 tok.pushBack(); 2151 switch (tt) { 2152 case '-': 2153 case '+': 2154 case ')': 2155 case ',': 2156 logger.debug("b, = {}", b); 2157 a = a.sum(b); 2158 b = a1; 2159 break; 2160 case '*': 2161 logger.debug("b, = {}", b); 2162 //a = a.sum(b); 2163 //b = a1; 2164 break; 2165 case '\n': 2166 tt = tok.nextToken(); 2167 logger.debug("tt,nl = {}", tt); 2168 break; 2169 default: // skip or finish ? 2170 logger.debug("default: {}", tok); 2171 } 2172 } 2173 logger.debug("b = {}", b); 2174 a = a.sum(b); 2175 logger.info("nextExteriorPolynomial = {}", a); 2176 // b = a1; 2177 return a; 2178 } 2179 2180 2181 /** 2182 * Parsing method for exterior polynomial list. Syntax: 2183 * <pre> 2184 * ( p1, p2, p3, ..., pn ) 2185 * </pre> 2186 * 2187 * @return the next exterior polynomial list. 2188 * @throws IOException 2189 */ 2190 @SuppressWarnings("unchecked") 2191 public List<GenExteriorPolynomial> nextExteriorPolynomialList() throws IOException { 2192 GenExteriorPolynomialRing wfac = new GenExteriorPolynomialRing(pfac); 2193 return nextExteriorPolynomialList(wfac); 2194 } 2195 2196 2197 /** 2198 * Parsing method for exterior polynomial list. Syntax: 2199 * <pre> 2200 * ( p1, p2, p3, ..., pn ) 2201 * </pre> 2202 * 2203 * @param wfac exterior polynomial ring. 2204 * @return the next exterior polynomial list. 2205 * @throws IOException 2206 */ 2207 public List<GenExteriorPolynomial> nextExteriorPolynomialList(GenExteriorPolynomialRing wfac) throws IOException { 2208 GenExteriorPolynomial a; 2209 List<GenExteriorPolynomial> L = new ArrayList<GenExteriorPolynomial>(); 2210 int tt; 2211 tt = tok.nextToken(); 2212 if (tt == StreamTokenizer.TT_EOF) 2213 return L; 2214 if (tt != '(') 2215 return L; 2216 logger.debug("exterior polynomial list"); 2217 while (true) { 2218 tt = tok.nextToken(); 2219 if (tok.ttype == ',') 2220 continue; 2221 if (tt == '(') { 2222 a = nextExteriorPolynomial(wfac); 2223 tt = tok.nextToken(); 2224 if (tok.ttype != ')') 2225 tok.pushBack(); 2226 } else { 2227 tok.pushBack(); 2228 a = nextExteriorPolynomial(wfac); 2229 } 2230 logger.info("next pol = {}", a); 2231 L.add(a); 2232 if (tok.ttype == StreamTokenizer.TT_EOF) 2233 break; 2234 if (tok.ttype == ')') 2235 break; 2236 } 2237 return L; 2238 } 2239 2240 2241 // must also allow +/- // does not work with tokenizer 2242 //private static boolean number(char x) { 2243 // return digit(x) || x == '-' || x == '+'; 2244 //} 2245 2246 2247 static boolean digit(char x) { 2248 return '0' <= x && x <= '9'; 2249 } 2250 2251 2252 static boolean letter(char x) { 2253 return ('a' <= x && x <= 'z') || ('A' <= x && x <= 'Z'); 2254 } 2255 2256 2257 // unused 2258 public void nextComma() throws IOException { 2259 int tt; 2260 if (tok.ttype == ',') { 2261 tt = tok.nextToken(); 2262 logger.debug("after comma: {}", tt); 2263 } 2264 } 2265 2266 2267 /** 2268 * Parse variable list from String. 2269 * @param s String. Syntax: 2270 * 2271 * <pre> 2272 * (n1,...,nk) 2273 * </pre> 2274 * 2275 * or 2276 * 2277 * <pre> 2278 * (n1 ... nk) 2279 * </pre> 2280 * 2281 * parenthesis are optional. 2282 * @return array of variable names found in s. 2283 */ 2284 public static String[] variableList(String s) { 2285 String[] vl = null; 2286 if (s == null) { 2287 return vl; 2288 } 2289 String st = s.trim(); 2290 if (st.length() == 0) { 2291 return new String[0]; 2292 } 2293 if (st.charAt(0) == '(') { 2294 st = st.substring(1); 2295 } 2296 if (st.charAt(st.length() - 1) == ')') { 2297 st = st.substring(0, st.length() - 1); 2298 } 2299 st = st.replaceAll(",", " "); 2300 List<String> sl = new ArrayList<String>(); 2301 Scanner sc = new Scanner(st); 2302 while (sc.hasNext()) { 2303 String sn = sc.next(); 2304 sl.add(sn); 2305 } 2306 sc.close(); 2307 vl = new String[sl.size()]; 2308 int i = 0; 2309 for (String si : sl) { 2310 vl[i] = si; 2311 i++; 2312 } 2313 return vl; 2314 } 2315 2316 2317 /** 2318 * Extract variable list from expression. 2319 * @param s String. Syntax: any polynomial expression. 2320 * @return array of variable names found in s. 2321 */ 2322 public static String[] expressionVariables(String s) { 2323 String[] vl = null; 2324 if (s == null) { 2325 return vl; 2326 } 2327 String st = s.trim(); 2328 if (st.length() == 0) { 2329 return new String[0]; 2330 } 2331 st = st.replaceAll(",", " "); 2332 st = st.replaceAll("\\+", " "); 2333 st = st.replaceAll("-", " "); 2334 st = st.replaceAll("\\*", " "); 2335 st = st.replaceAll("/", " "); 2336 st = st.replaceAll("\\(", " "); 2337 st = st.replaceAll("\\)", " "); 2338 st = st.replaceAll("\\{", " "); 2339 st = st.replaceAll("\\}", " "); 2340 st = st.replaceAll("\\[", " "); 2341 st = st.replaceAll("\\]", " "); 2342 st = st.replaceAll("\\^", " "); 2343 //System.out.println("st = " + st); 2344 2345 Set<String> sl = new TreeSet<String>(); 2346 Scanner sc = new Scanner(st); 2347 while (sc.hasNext()) { 2348 String sn = sc.next(); 2349 if (sn == null || sn.length() == 0) { 2350 continue; 2351 } 2352 //System.out.println("sn = " + sn); 2353 int i = 0; 2354 while (digit(sn.charAt(i)) && i < sn.length() - 1) { 2355 i++; 2356 } 2357 //System.out.println("sn = " + sn + ", i = " + i); 2358 if (i > 0) { 2359 sn = sn.substring(i, sn.length()); 2360 } 2361 //System.out.println("sn = " + sn); 2362 if (sn.length() == 0) { 2363 continue; 2364 } 2365 if (!letter(sn.charAt(0))) { 2366 continue; 2367 } 2368 //System.out.println("sn = " + sn); 2369 sl.add(sn); 2370 } 2371 sc.close(); 2372 vl = new String[sl.size()]; 2373 int i = 0; 2374 for (String si : sl) { 2375 vl[i] = si; 2376 i++; 2377 } 2378 return vl; 2379 } 2380 2381}