001/* 002 * $Id: GenWordPolynomialRing.java 5888 2018-07-29 20:58:45Z kredel $ 003 */ 004 005package edu.jas.poly; 006 007 008import java.io.Reader; 009import java.io.IOException; 010import java.io.StringReader; 011import java.math.BigInteger; 012import java.util.ArrayList; 013import java.util.List; 014import java.util.Arrays; 015import java.util.Map; 016import java.util.Random; 017 018import org.apache.logging.log4j.Logger; 019import org.apache.logging.log4j.LogManager; 020 021import edu.jas.kern.PreemptStatus; 022import edu.jas.kern.Scripting; 023import edu.jas.structure.RingElem; 024import edu.jas.structure.RingFactory; 025 026 027/** 028 * GenWordPolynomialRing generic polynomial factory implementing RingFactory; 029 * Factory for non-commutative string polynomials over C. 030 * @param <C> coefficient type 031 * @author Heinz Kredel 032 */ 033 034public final class GenWordPolynomialRing<C extends RingElem<C>> implements RingFactory<GenWordPolynomial<C>> 035/*, Iterable<GenWordPolynomial<C>>*/{ 036 037 038 /** 039 * The factory for the coefficients. 040 */ 041 public final RingFactory<C> coFac; 042 043 044 /** 045 * The factory for the alphabet. 046 */ 047 public final WordFactory alphabet; 048 049 050 /** 051 * The constant polynomial 0 for this ring. 052 */ 053 public final GenWordPolynomial<C> ZERO; 054 055 056 /** 057 * The constant polynomial 1 for this ring. 058 */ 059 public final GenWordPolynomial<C> ONE; 060 061 062 /** 063 * The constant empty word exponent for this ring. 064 */ 065 public final Word wone; 066 067 068 /** 069 * A default random sequence generator. 070 */ 071 final static Random random = new Random(); 072 073 074 /** 075 * Indicator if this ring is a field. 076 */ 077 private int isField = -1; // initially unknown 078 079 080 /** 081 * Log4j logger object. 082 */ 083 private static final Logger logger = LogManager.getLogger(GenWordPolynomialRing.class); 084 085 086 /** 087 * Flag to enable if preemptive interrrupt is checked. 088 */ 089 final boolean checkPreempt = PreemptStatus.isAllowed(); 090 091 092 /** 093 * The constructor creates a polynomial factory object with the default term 094 * order. 095 * @param cf factory for coefficients of type C. 096 * @param wf factory for strings. 097 */ 098 public GenWordPolynomialRing(RingFactory<C> cf, WordFactory wf) { 099 coFac = cf; 100 alphabet = wf; 101 ZERO = new GenWordPolynomial<C>(this); 102 C coeff = coFac.getONE(); 103 wone = wf.getONE(); 104 ONE = new GenWordPolynomial<C>(this, coeff, wone); 105 } 106 107 108 /** 109 * The constructor creates a polynomial factory object. 110 * @param cf factory for coefficients of type C. 111 * @param s array of variable names. 112 */ 113 public GenWordPolynomialRing(RingFactory<C> cf, String[] s) { 114 this(cf, new WordFactory(s)); 115 } 116 117 118 /** 119 * The constructor creates a polynomial factory object. 120 * @param cf factory for coefficients of type C. 121 * @param s string of single letter variable names. 122 */ 123 public GenWordPolynomialRing(RingFactory<C> cf, String s) { 124 this(cf, new WordFactory(s)); 125 } 126 127 128 /** 129 * The constructor creates a polynomial factory object. 130 * @param cf factory for coefficients of type C. 131 * @param o other polynomial ring. 132 */ 133 public GenWordPolynomialRing(RingFactory<C> cf, GenWordPolynomialRing o) { 134 this(cf, o.alphabet); 135 } 136 137 138 /** 139 * The constructor creates a polynomial factory object. 140 * @param fac polynomial ring. 141 */ 142 public GenWordPolynomialRing(GenPolynomialRing<C> fac) { 143 this(fac.coFac, new WordFactory(fac.vars)); 144 } 145 146 147 /** 148 * Copy this factory. 149 * @return a clone of this. 150 */ 151 public GenWordPolynomialRing<C> copy() { 152 return new GenWordPolynomialRing<C>(coFac, this); 153 } 154 155 156 /** 157 * Get the String representation. 158 * @see java.lang.Object#toString() 159 */ 160 @Override 161 public String toString() { 162 StringBuffer s = new StringBuffer(); 163 s.append("WordPolyRing("); 164 if (coFac instanceof RingElem) { 165 s.append(((RingElem<C>) coFac).toScriptFactory()); 166 } else { 167 s.append(coFac.toString().trim()); 168 } 169 s.append(","); 170 s.append(alphabet.toString()); 171 s.append(")"); 172 return s.toString(); 173 } 174 175 176 /** 177 * Get a scripting compatible string representation. 178 * @return script compatible representation for this Element. 179 * @see edu.jas.structure.Element#toScript() 180 */ 181 @Override 182 public String toScript() { 183 StringBuffer s = new StringBuffer(); 184 switch (Scripting.getLang()) { 185 case Ruby: 186 s.append("WordPolyRing.new("); 187 break; 188 case Python: 189 default: 190 s.append("WordPolyRing("); 191 } 192 if (coFac instanceof RingElem) { 193 s.append(((RingElem<C>) coFac).toScriptFactory()); 194 } else { 195 s.append(coFac.toScript().trim()); 196 } 197 s.append(","); 198 s.append(alphabet.toScript()); 199 s.append(")"); 200 return s.toString(); 201 } 202 203 204 /** 205 * Extend variables. Used e.g. in module embedding. Extend number of 206 * variables by i. 207 * @param i number of variables to extend. 208 * @return extended word polynomial ring factory. 209 */ 210 public GenWordPolynomialRing<C> extend(int i) { 211 // add module variable names 212 String[] v = GenPolynomialRing.newVars("t", i); 213 return extend(v); 214 } 215 216 217 /** 218 * Extend variables. Extend number of variables by length(vn). 219 * @param vn names for extended variables. 220 * @return extended polynomial ring factory. 221 */ 222 public GenWordPolynomialRing<C> extend(String[] vn) { 223 WordFactory wfe = alphabet.extend(vn); 224 return new GenWordPolynomialRing<C>(coFac, wfe); 225 } 226 227 228 /** 229 * Comparison with any other object. 230 * @see java.lang.Object#equals(java.lang.Object) 231 */ 232 @Override 233 @SuppressWarnings("unchecked") 234 public boolean equals(Object other) { 235 if (other == null) { 236 return false; 237 } 238 if (!(other instanceof GenWordPolynomialRing)) { 239 return false; 240 } 241 GenWordPolynomialRing<C> oring = (GenWordPolynomialRing<C>) other; 242 if (!coFac.equals(oring.coFac)) { 243 return false; 244 } 245 if (!alphabet.equals(oring.alphabet)) { 246 return false; 247 } 248 return true; 249 } 250 251 252 /** 253 * Hash code for this polynomial ring. 254 * @see java.lang.Object#hashCode() 255 */ 256 @Override 257 public int hashCode() { 258 int h; 259 h = (coFac.hashCode() << 11); 260 h += alphabet.hashCode(); 261 return h; 262 } 263 264 265 /** 266 * Get the variable names. 267 * @return vars. 268 */ 269 public String[] getVars() { 270 return alphabet.getVars(); // Java-5: Arrays.copyOf(vars,vars.length); 271 } 272 273 274 /** 275 * Get the zero element from the coefficients. 276 * @return 0 as C. 277 */ 278 public C getZEROCoefficient() { 279 return coFac.getZERO(); 280 } 281 282 283 /** 284 * Get the one element from the coefficients. 285 * @return 1 as C. 286 */ 287 public C getONECoefficient() { 288 return coFac.getONE(); 289 } 290 291 292 /** 293 * Get the zero element. 294 * @return 0 as GenWordPolynomial<C>. 295 */ 296 public GenWordPolynomial<C> getZERO() { 297 return ZERO; 298 } 299 300 301 /** 302 * Get the one element. 303 * @return 1 as GenWordPolynomial<C>. 304 */ 305 public GenWordPolynomial<C> getONE() { 306 return ONE; 307 } 308 309 310 /** 311 * Query if this ring is commutative. 312 * @return true if this ring is commutative, else false. 313 */ 314 public boolean isCommutative() { 315 return coFac.isCommutative() && alphabet.isFinite(); 316 } 317 318 319 /** 320 * Query if this ring is associative. 321 * @return true if this ring is associative, else false. 322 */ 323 public boolean isAssociative() { 324 return coFac.isAssociative(); 325 } 326 327 328 /** 329 * Is this structure finite or infinite. 330 * @return true if this structure is finite, else false. 331 * @see edu.jas.structure.ElemFactory#isFinite() 332 */ 333 public boolean isFinite() { 334 return alphabet.isFinite() && coFac.isFinite(); 335 } 336 337 338 /** 339 * Query if this ring is a field. 340 * @return false. 341 */ 342 public boolean isField() { 343 if (isField > 0) { 344 return true; 345 } 346 if (isField == 0) { 347 return false; 348 } 349 if (coFac.isField() && alphabet.isFinite()) { 350 isField = 1; 351 return true; 352 } 353 isField = 0; 354 return false; 355 } 356 357 358 /** 359 * Characteristic of this ring. 360 * @return characteristic of this ring. 361 */ 362 public java.math.BigInteger characteristic() { 363 return coFac.characteristic(); 364 } 365 366 367 /** 368 * Get a (constant) GenWordPolynomial<C> element from a coefficient 369 * value. 370 * @param a coefficient. 371 * @return a GenWordPolynomial<C>. 372 */ 373 public GenWordPolynomial<C> valueOf(C a) { 374 return new GenWordPolynomial<C>(this, a); 375 } 376 377 378 /** 379 * Get a GenWordPolynomial<C> element from a word. 380 * @param e word. 381 * @return a GenWordPolynomial<C>. 382 */ 383 public GenWordPolynomial<C> valueOf(Word e) { 384 return valueOf(coFac.getONE(), e); 385 } 386 387 388 /** 389 * Get a GenWordPolynomial<C> element from an ExpVector. 390 * @param e exponent vector. 391 * @return a GenWordPolynomial<C>. 392 */ 393 public GenWordPolynomial<C> valueOf(ExpVector e) { 394 return valueOf(coFac.getONE(), e); 395 } 396 397 398 /** 399 * Get a GenWordPolynomial<C> element from a coeffcient and a word. 400 * @param a coefficient. 401 * @param e word. 402 * @return a GenWordPolynomial<C>. 403 */ 404 public GenWordPolynomial<C> valueOf(C a, Word e) { 405 return new GenWordPolynomial<C>(this, a, e); 406 } 407 408 409 /** 410 * Get a GenWordPolynomial<C> element from a coeffcient and an ExpVector. 411 * @param a coefficient. 412 * @param e exponent vector. 413 * @return a GenWordPolynomial<C>. 414 */ 415 public GenWordPolynomial<C> valueOf(C a, ExpVector e) { 416 return new GenWordPolynomial<C>(this, a, alphabet.valueOf(e)); 417 } 418 419 420 /** 421 * Get a GenWordPolynomial<C> element from a GenPolynomial<C>. 422 * @param a GenPolynomial. 423 * @return a GenWordPolynomial<C>. 424 */ 425 public GenWordPolynomial<C> valueOf(GenPolynomial<C> a) { 426 if (a.isZERO()) { 427 return getZERO(); 428 } 429 if (a.isONE()) { 430 return getONE(); 431 } 432 GenWordPolynomial<C> p = this.getZERO().copy(); 433 for (Map.Entry<ExpVector, C> m : a.val.entrySet()) { 434 C c = m.getValue(); 435 ExpVector e = m.getKey(); 436 Word w = alphabet.valueOf(e); 437 p.doPutToMap(w, c); 438 } 439 return p; 440 } 441 442 443 /** 444 * Get a GenWordPolynomial<C> element from a GenWordPolynomial<C>. 445 * @param a GenWordPolynomial. 446 * @return a GenWordPolynomial<C>. 447 */ 448 public GenWordPolynomial<C> valueOf(GenWordPolynomial<C> a) { 449 if (a.isZERO()) { 450 return getZERO(); 451 } 452 if (a.isONE()) { 453 return getONE(); 454 } 455 GenWordPolynomial<C> p = this.getZERO().copy(); 456 for (Map.Entry<Word, C> m : a.val.entrySet()) { 457 C c = m.getValue(); 458 Word e = m.getKey(); 459 Word w = alphabet.valueOf(e); 460 p.doPutToMap(w, c); 461 } 462 return p; 463 } 464 465 466 /** 467 * Get a list of GenWordPolynomial<C> element from a list of 468 * GenPolynomial<C>. 469 * @param A GenPolynomial list. 470 * @return a GenWordPolynomial<C> list. 471 */ 472 public List<GenWordPolynomial<C>> valueOf(List<GenPolynomial<C>> A) { 473 List<GenWordPolynomial<C>> B = new ArrayList<GenWordPolynomial<C>>(A.size()); 474 if (A.isEmpty()) { 475 return B; 476 } 477 for (GenPolynomial<C> a : A) { 478 GenWordPolynomial<C> b = valueOf(a); 479 B.add(b); 480 } 481 return B; 482 } 483 484 485 /** 486 * Get a (constant) GenWordPolynomial<C> element from a long value. 487 * @param a long. 488 * @return a GenWordPolynomial<C>. 489 */ 490 public GenWordPolynomial<C> fromInteger(long a) { 491 return new GenWordPolynomial<C>(this, coFac.fromInteger(a), wone); 492 } 493 494 495 /** 496 * Get a (constant) GenWordPolynomial<C> element from a BigInteger 497 * value. 498 * @param a BigInteger. 499 * @return a GenWordPolynomial<C>. 500 */ 501 public GenWordPolynomial<C> fromInteger(BigInteger a) { 502 return new GenWordPolynomial<C>(this, coFac.fromInteger(a), wone); 503 } 504 505 506 /** 507 * Random polynomial. Generates a random polynomial. 508 * @param n number of terms. 509 * @return a random polynomial. 510 */ 511 public GenWordPolynomial<C> random(int n) { 512 return random(n, random); 513 } 514 515 516 /** 517 * Random polynomial. Generates a random polynomial with k = 5, l = n, d = 518 * 3. 519 * @param n number of terms. 520 * @param rnd is a source for random bits. 521 * @return a random polynomial. 522 */ 523 public GenWordPolynomial<C> random(int n, Random rnd) { 524 return random(5, n, 3, rnd); 525 } 526 527 528 /** 529 * Generate a random polynomial. 530 * @param k bitsize of random coefficients. 531 * @param l number of terms. 532 * @param d maximal length of a random word. 533 * @return a random polynomial. 534 */ 535 public GenWordPolynomial<C> random(int k, int l, int d) { 536 return random(k, l, d, random); 537 } 538 539 540 /** 541 * Generate a random polynomial. 542 * @param k bitsize of random coefficients. 543 * @param l number of terms. 544 * @param d maximal length of a random word. 545 * @param rnd is a source for random bits. 546 * @return a random polynomial. 547 */ 548 public GenWordPolynomial<C> random(int k, int l, int d, Random rnd) { 549 GenWordPolynomial<C> r = getZERO(); //.clone() or copy( ZERO ); 550 // add l random coeffs and words of maximal length d 551 for (int i = 0; i < l; i++) { 552 int di = Math.abs(rnd.nextInt() % d); 553 Word e = alphabet.random(di, rnd); 554 C a = coFac.random(k, rnd); 555 r = r.sum(a, e); // somewhat inefficient but clean 556 //System.out.println("e = " + e + " a = " + a); 557 } 558 return r; 559 } 560 561 562 /** 563 * Copy polynomial c. 564 * @param c polynomial to copy. 565 * @return a copy of c. 566 */ 567 public GenWordPolynomial<C> copy(GenWordPolynomial<C> c) { 568 return new GenWordPolynomial<C>(this, c.val); 569 } 570 571 572 /** 573 * Parse a polynomial with the use of GenWordPolynomialTokenizer. 574 * @param s String. 575 * @return GenWordPolynomial from s. 576 */ 577 public GenWordPolynomial<C> parse(String s) { 578 String val = s; 579 if (!s.contains("|")) { 580 val = val.replace("{", "").replace("}", ""); 581 } 582 return parse(new StringReader(val)); 583 } 584 585 586 /** 587 * Parse a polynomial with the use of GenWordPolynomialTokenizer. 588 * @param r Reader. 589 * @return next GenWordPolynomial from r. 590 */ 591 @SuppressWarnings("unchecked") 592 public GenWordPolynomial<C> parse(Reader r) { 593 if (alphabet.length() <= 4) { // todo, hack for commuative like cases 594 GenPolynomialRing<C> cr = new GenPolynomialRing<C>(coFac, alphabet.getVars() ); 595 GenPolynomialTokenizer pt = new GenPolynomialTokenizer(cr, r); 596 GenPolynomial<C> p = cr.getZERO(); 597 try { 598 p = pt.nextPolynomial(); 599 } catch (IOException e) { 600 logger.error(e.toString() + " parse " + this); 601 } 602 GenWordPolynomial<C> wp = this.valueOf(p); 603 return wp; 604 } 605 logger.error("parse not implemented"); 606 throw new UnsupportedOperationException("not implemented"); 607 } 608 609 610 /** 611 * Generate univariate polynomial in a given variable. 612 * @param i the index of the variable. 613 * @return X_i as univariate polynomial. 614 */ 615 public GenWordPolynomial<C> univariate(int i) { 616 GenWordPolynomial<C> p = getZERO(); 617 List<Word> wgen = alphabet.generators(); 618 if (0 <= i && i < wgen.size()) { 619 C one = coFac.getONE(); 620 Word f = wgen.get(i); 621 p = p.sum(one, f); 622 } 623 return p; 624 } 625 626 627 /** 628 * Generate commute polynomial in two variables. 629 * @param i the index of the first variable. 630 * @param j the index of the second variable. 631 * @return X_i * x_j - X_j * X_i as polynomial. 632 */ 633 public GenWordPolynomial<C> commute(int i, int j) { 634 GenWordPolynomial<C> p = getZERO(); 635 List<Word> wgen = alphabet.generators(); 636 if (0 <= i && i < wgen.size() && 0 <= j && j < wgen.size()) { 637 C one = coFac.getONE(); 638 Word f = wgen.get(i); 639 Word e = wgen.get(j); 640 p = p.sum(one, e.multiply(f)); 641 p = p.subtract(one, f.multiply(e)); 642 if (i > j) { 643 p = p.negate(); 644 } 645 } 646 return p; 647 } 648 649 650 /** 651 * Generate commute polynomials for given variable. 652 * @param i the index of the variable. 653 * @return [X_i * x_j - X_j * X_i, i != j] as list of polynomials. 654 */ 655 public List<GenWordPolynomial<C>> commute(int i) { 656 int n = alphabet.length(); 657 List<GenWordPolynomial<C>> pols = new ArrayList<GenWordPolynomial<C>>(n-1); 658 for ( int j = 0; j < n; j++ ) { 659 if (i != j) { 660 pols.add(commute(i,j)); 661 } 662 } 663 return pols; 664 } 665 666 667 /** 668 * Generate commute polynomials for all variables. 669 * @return [X_i * x_j - X_j * X_i, i != j] as list of polynomials. 670 */ 671 public List<GenWordPolynomial<C>> commute() { 672 int n = alphabet.length(); 673 List<GenWordPolynomial<C>> pols = new ArrayList<GenWordPolynomial<C>>(n*(n-1)); 674 for ( int i = 0; i < n; i++ ) { 675 pols.addAll( commute(i) ); 676 } 677 return pols; 678 } 679 680 681 /** 682 * Generate list of univariate polynomials in all variables. 683 * @return List(X_1,...,X_n) a list of univariate polynomials. 684 */ 685 public List<GenWordPolynomial<C>> univariateList() { 686 int n = alphabet.length(); 687 List<GenWordPolynomial<C>> pols = new ArrayList<GenWordPolynomial<C>>(n); 688 for (int i = 0; i < n; i++) { 689 GenWordPolynomial<C> p = univariate(i); 690 pols.add(p); 691 } 692 return pols; 693 } 694 695 696 /** 697 * Get the generating elements <b>excluding</b> the generators for the 698 * coefficient ring. 699 * @return a list of generating elements for this ring. 700 */ 701 public List<GenWordPolynomial<C>> getGenerators() { 702 List<GenWordPolynomial<C>> univs = univariateList(); 703 List<GenWordPolynomial<C>> gens = new ArrayList<GenWordPolynomial<C>>(univs.size() + 1); 704 gens.add(getONE()); 705 gens.addAll(univs); 706 return gens; 707 } 708 709 710 /** 711 * Get a list of all generating elements. 712 * @return list of generators for the algebraic structure. 713 * @see edu.jas.structure.ElemFactory#generators() 714 */ 715 public List<GenWordPolynomial<C>> generators() { 716 List<C> cogens = coFac.generators(); 717 List<GenWordPolynomial<C>> univs = univariateList(); 718 List<GenWordPolynomial<C>> gens = new ArrayList<GenWordPolynomial<C>>(univs.size() + cogens.size()); 719 for (C c : cogens) { 720 gens.add(getONE().multiply(c)); 721 } 722 gens.addAll(univs); 723 return gens; 724 } 725 726}