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