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