001/* 002 * $Id: Product.java 4125 2012-08-19 19:05:22Z kredel $ 003 */ 004 005package edu.jas.arith; 006 007 008import java.util.Iterator; 009import java.util.Map; 010import java.util.SortedMap; 011import java.util.TreeMap; 012 013import org.apache.log4j.Logger; 014 015import edu.jas.structure.NotInvertibleException; 016import edu.jas.structure.RegularRingElem; 017import edu.jas.structure.RingElem; 018import edu.jas.structure.RingFactory; 019 020 021/** 022 * Direct product element based on RingElem. Objects of this class are (nearly) 023 * immutable. 024 * @author Heinz Kredel 025 */ 026public class Product<C extends RingElem<C>> implements RegularRingElem<Product<C>> { 027 028 029 private static final Logger logger = Logger.getLogger(Product.class); 030 031 032 //private final boolean debug = logger.isDebugEnabled(); 033 034 035 /** 036 * Product class factory data structure. 037 */ 038 public final ProductRing<C> ring; 039 040 041 /** 042 * Value part of the element data structure. 043 */ 044 public final SortedMap<Integer, C> val; 045 046 047 /** 048 * Flag to remember if this product element is a unit in each cmponent. -1 049 * is unknown, 1 is unit, 0 not a unit. 050 */ 051 protected int isunit = -1; // initially unknown 052 053 054 /** 055 * The constructor creates a Product object from a ring factory. 056 * @param r ring factory. 057 */ 058 public Product(ProductRing<C> r) { 059 this(r, new TreeMap<Integer, C>(), 0); 060 } 061 062 063 /** 064 * The constructor creates a Product object from a ring factory and a ring 065 * element. 066 * @param r ring factory. 067 * @param a ring element. 068 */ 069 public Product(ProductRing<C> r, SortedMap<Integer, C> a) { 070 this(r, a, -1); 071 } 072 073 074 /** 075 * The constructor creates a Product object from a ring factory, a ring 076 * element and an indicator if a is a unit. 077 * @param r ring factory. 078 * @param a ring element. 079 * @param u isunit indicator, -1, 0, 1. 080 */ 081 public Product(ProductRing<C> r, SortedMap<Integer, C> a, int u) { 082 ring = r; 083 val = a; 084 isunit = u; 085 } 086 087 088 /** 089 * Get component. 090 * @param i index of component. 091 * @return val(i). 092 */ 093 public C get(int i) { 094 return val.get(i); // auto-boxing 095 } 096 097 098 /** 099 * Get the corresponding element factory. 100 * @return factory for this Element. 101 * @see edu.jas.structure.Element#factory() 102 */ 103 public ProductRing<C> factory() { 104 return ring; 105 } 106 107 108 /** 109 * Clone this. 110 * @see java.lang.Object#clone() 111 */ 112 @Override 113 public Product<C> copy() { 114 return new Product<C>(ring, val, isunit); 115 } 116 117 118 /** 119 * Is Product zero. 120 * @return If this is 0 then true is returned, else false. 121 * @see edu.jas.structure.RingElem#isZERO() 122 */ 123 public boolean isZERO() { 124 return val.size() == 0; 125 } 126 127 128 /** 129 * Is Product one. 130 * @return If this is 1 then true is returned, else false. 131 * @see edu.jas.structure.RingElem#isONE() 132 */ 133 public boolean isONE() { 134 if (val.size() != ring.length()) { 135 return false; 136 } 137 for (C e : val.values()) { 138 if (!e.isONE()) { 139 return false; 140 } 141 } 142 return true; 143 } 144 145 146 /** 147 * Is Product full. 148 * @return If every component is non-zero, then true is returned, else 149 * false. 150 */ 151 public boolean isFull() { 152 if (val.size() != ring.length()) { 153 return false; 154 } 155 return true; 156 } 157 158 159 /** 160 * Is Product unit. 161 * @return If this is a unit then true is returned, else false. 162 * @see edu.jas.structure.RingElem#isUnit() 163 */ 164 public boolean isUnit() { 165 if (isunit > 0) { 166 return true; 167 } 168 if (isunit == 0) { 169 return false; 170 } 171 if (isZERO()) { 172 isunit = 0; 173 return false; 174 } 175 for (C e : val.values()) { 176 if (!e.isUnit()) { 177 isunit = 0; 178 return false; 179 } 180 } 181 isunit = 1; 182 return true; 183 } 184 185 186 /** 187 * Is Product idempotent. 188 * @return If this is a idempotent element then true is returned, else 189 * false. 190 */ 191 public boolean isIdempotent() { 192 for (C e : val.values()) { 193 if (!e.isONE()) { 194 return false; 195 } 196 } 197 return true; 198 } 199 200 201 /** 202 * Get the String representation as RingElem. 203 * @see java.lang.Object#toString() 204 */ 205 @Override 206 public String toString() { 207 return val.toString(); 208 } 209 210 211 /** 212 * Get a scripting compatible string representation. 213 * @return script compatible representation for this Element. 214 * @see edu.jas.structure.Element#toScript() 215 */ 216 //JAVA6only: @Override 217 public String toScript() { 218 // Python case 219 StringBuffer s = new StringBuffer("( "); 220 boolean first = true; 221 for (Integer i : val.keySet()) { 222 C v = val.get(i); 223 if (first) { 224 first = false; 225 } else { 226 if (v.signum() < 0) { 227 s.append(" - "); 228 v = v.negate(); 229 } else { 230 s.append(" + "); 231 } 232 } 233 if (!v.isONE()) { 234 s.append(v.toScript() + "*"); 235 } 236 s.append("pg" + i); 237 } 238 s.append(" )"); 239 return s.toString(); 240 } 241 242 243 /** 244 * Get a scripting compatible string representation of the factory. 245 * @return script compatible representation for this ElemFactory. 246 * @see edu.jas.structure.Element#toScriptFactory() 247 */ 248 //JAVA6only: @Override 249 public String toScriptFactory() { 250 // Python case 251 return factory().toScript(); 252 } 253 254 255 /** 256 * Product comparison. 257 * @param b Product. 258 * @return sign(this-b). 259 */ 260 //JAVA6only: @Override 261 public int compareTo(Product<C> b) { 262 if (!ring.equals(b.ring)) { 263 logger.info("other ring " + b.ring); 264 throw new IllegalArgumentException("rings not comparable " + this); 265 } 266 SortedMap<Integer, C> v = b.val; 267 Iterator<Map.Entry<Integer, C>> ti = val.entrySet().iterator(); 268 Iterator<Map.Entry<Integer, C>> bi = v.entrySet().iterator(); 269 int s; 270 while (ti.hasNext() && bi.hasNext()) { 271 Map.Entry<Integer, C> te = ti.next(); 272 Map.Entry<Integer, C> be = bi.next(); 273 s = te.getKey().compareTo(be.getKey()); 274 if (s != 0) { 275 return s; 276 } 277 s = te.getValue().compareTo(be.getValue()); 278 if (s != 0) { 279 return s; 280 } 281 } 282 if (ti.hasNext()) { 283 return -1; 284 } 285 if (bi.hasNext()) { 286 return 1; 287 } 288 return 0; 289 } 290 291 292 /** 293 * Comparison with any other object. 294 * @see java.lang.Object#equals(java.lang.Object) 295 */ 296 @SuppressWarnings("unchecked") 297 @Override 298 public boolean equals(Object b) { 299 if (!(b instanceof Product)) { 300 return false; 301 } 302 Product<C> a = null; 303 try { 304 a = (Product<C>) b; 305 } catch (ClassCastException e) { 306 } 307 if (a == null) { 308 return false; 309 } 310 return (0 == compareTo(a)); 311 } 312 313 314 /** 315 * Hash code for this local. 316 * @see java.lang.Object#hashCode() 317 */ 318 @Override 319 public int hashCode() { 320 int h = ring.hashCode(); 321 h = 37 * h + val.hashCode(); 322 return h; 323 } 324 325 326 /** 327 * Product extend. Add new component j with value of component i. 328 * @param i from index. 329 * @param j to index. 330 * @return the extended value of this. 331 */ 332 public Product<C> extend(int i, int j) { 333 RingFactory<C> rf = ring.getFactory(j); 334 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); 335 C v = val.get(i); 336 C w = rf.copy(v); // valueOf 337 if (!w.isZERO()) { 338 elem.put(j, w); 339 } 340 return new Product<C>(ring, elem, isunit); 341 } 342 343 344 /** 345 * Product absolute value. 346 * @return the absolute value of this. 347 * @see edu.jas.structure.RingElem#abs() 348 */ 349 public Product<C> abs() { 350 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 351 for (Integer i : val.keySet()) { 352 C v = val.get(i).abs(); 353 elem.put(i, v); 354 } 355 return new Product<C>(ring, elem, isunit); 356 } 357 358 359 /** 360 * Product summation. 361 * @param S Product. 362 * @return this+S. 363 */ 364 public Product<C> sum(Product<C> S) { 365 if (S == null || S.isZERO()) { 366 return this; 367 } 368 if (this.isZERO()) { 369 return S; 370 } 371 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); // clone 372 SortedMap<Integer, C> sel = S.val; 373 for (Map.Entry<Integer, C> is : sel.entrySet()) { 374 Integer i = is.getKey(); 375 C x = elem.get(i); 376 C y = is.getValue(); //sel.get( i ); // assert y != null 377 if (x != null) { 378 x = x.sum(y); 379 if (!x.isZERO()) { 380 elem.put(i, x); 381 } else { 382 elem.remove(i); 383 } 384 } else { 385 elem.put(i, y); 386 } 387 } 388 return new Product<C>(ring, elem); 389 } 390 391 392 /** 393 * Product negate. 394 * @return -this. 395 * @see edu.jas.structure.RingElem#negate() 396 */ 397 public Product<C> negate() { 398 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 399 for (Integer i : val.keySet()) { 400 C v = val.get(i).negate(); 401 elem.put(i, v); 402 } 403 return new Product<C>(ring, elem, isunit); 404 } 405 406 407 /** 408 * Product signum. 409 * @see edu.jas.structure.RingElem#signum() 410 * @return signum of first non-zero component. 411 */ 412 public int signum() { 413 if (val.size() == 0) { 414 return 0; 415 } 416 C v = val.get(val.firstKey()); 417 return v.signum(); 418 } 419 420 421 /** 422 * Product subtraction. 423 * @param S Product. 424 * @return this-S. 425 */ 426 public Product<C> subtract(Product<C> S) { 427 return sum(S.negate()); 428 } 429 430 431 /** 432 * Product quasi-inverse. 433 * @see edu.jas.structure.RingElem#inverse() 434 * @return S with S = 1/this if defined. 435 */ 436 public Product<C> inverse() { 437 if (this.isZERO()) { 438 return this; 439 } 440 int isu = 0; 441 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 442 for (Integer i : val.keySet()) { 443 C x = val.get(i); // is non zero 444 try { 445 x = x.inverse(); 446 } catch (NotInvertibleException e) { 447 // could happen for e.g. ModInteger or AlgebraicNumber 448 x = null; //ring.getFactory(i).getZERO(); 449 } 450 if (x != null && !x.isZERO()) { // can happen 451 elem.put(i, x); 452 isu = 1; 453 } 454 } 455 return new Product<C>(ring, elem, isu); 456 } 457 458 459 /** 460 * Product idempotent. 461 * @return smallest S with this*S = this. 462 */ 463 public Product<C> idempotent() { 464 if (this.isZERO()) { 465 return this; 466 } 467 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 468 for (Integer i : val.keySet()) { 469 RingFactory<C> f = ring.getFactory(i); 470 C x = f.getONE(); 471 elem.put(i, x); 472 } 473 return new Product<C>(ring, elem, 1); 474 } 475 476 477 /** 478 * Product idempotent complement. 479 * @return 1-this.idempotent(). 480 */ 481 public Product<C> idemComplement() { 482 if (this.isZERO()) { 483 return ring.getONE(); 484 } 485 int isu = 0; 486 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 487 for (int i = 0; i < ring.length(); i++) { 488 C v = val.get(i); 489 if (v == null) { 490 RingFactory<C> f = ring.getFactory(i); 491 C x = f.getONE(); 492 elem.put(i, x); 493 isu = 1; 494 } 495 } 496 return new Product<C>(ring, elem, isu); 497 } 498 499 500 /** 501 * Product idempotent and. 502 * @param S Product. 503 * @return this.idempotent() and S.idempotent(). 504 */ 505 public Product<C> idempotentAnd(Product<C> S) { 506 if (this.isZERO() && S.isZERO()) { 507 return this; 508 } 509 int isu = 0; 510 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 511 for (int i = 0; i < ring.length(); i++) { 512 C v = val.get(i); 513 C w = S.val.get(i); 514 if (v != null && w != null) { 515 RingFactory<C> f = ring.getFactory(i); 516 C x = f.getONE(); 517 elem.put(i, x); 518 isu = 1; 519 } 520 } 521 return new Product<C>(ring, elem, isu); 522 } 523 524 525 /** 526 * Product idempotent or. 527 * @param S Product. 528 * @return this.idempotent() or S.idempotent(). 529 */ 530 public Product<C> idempotentOr(Product<C> S) { 531 if (this.isZERO() && S.isZERO()) { 532 return this; 533 } 534 int isu = 0; 535 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 536 for (int i = 0; i < ring.length(); i++) { 537 C v = val.get(i); 538 C w = S.val.get(i); 539 if (v != null || w != null) { 540 RingFactory<C> f = ring.getFactory(i); 541 C x = f.getONE(); 542 elem.put(i, x); 543 isu = 1; 544 } 545 } 546 return new Product<C>(ring, elem, isu); 547 } 548 549 550 /** 551 * Product fill with idempotent. 552 * @param S Product. 553 * @return fill this with S.idempotent(). 554 */ 555 public Product<C> fillIdempotent(Product<C> S) { 556 if (S.isZERO()) { 557 return this; 558 } 559 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); 560 for (int i = 0; i < ring.length(); i++) { 561 C v = elem.get(i); 562 if (v != null) { 563 continue; 564 } 565 C w = S.val.get(i); 566 if (w != null) { 567 RingFactory<C> f = ring.getFactory(i); 568 C x = f.getONE(); 569 elem.put(i, x); 570 } 571 } 572 return new Product<C>(ring, elem, isunit); 573 } 574 575 576 /** 577 * Product fill with one. 578 * @return fill this with one. 579 */ 580 public Product<C> fillOne() { 581 if (this.isFull()) { 582 return this; 583 } 584 if (this.isZERO()) { 585 return ring.getONE(); 586 } 587 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); 588 for (int i = 0; i < ring.length(); i++) { 589 C v = elem.get(i); 590 if (v != null) { 591 continue; 592 } 593 RingFactory<C> f = ring.getFactory(i); 594 C x = f.getONE(); 595 elem.put(i, x); 596 } 597 return new Product<C>(ring, elem, isunit); 598 } 599 600 601 /** 602 * Product quasi-division. 603 * @param S Product. 604 * @return this/S. 605 */ 606 public Product<C> divide(Product<C> S) { 607 if (S == null) { 608 return ring.getZERO(); 609 } 610 if (S.isZERO()) { 611 return S; 612 } 613 if (this.isZERO()) { 614 return this; 615 } 616 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 617 SortedMap<Integer, C> sel = S.val; 618 for (Integer i : val.keySet()) { 619 C y = sel.get(i); 620 if (y != null) { 621 C x = val.get(i); 622 try { 623 x = x.divide(y); 624 } catch (NotInvertibleException e) { 625 // should not happen any more 626 System.out.println("product divide error: x = " + x + ", y = " + y); 627 // could happen for e.g. ModInteger or AlgebraicNumber 628 x = null; //ring.getFactory(i).getZERO(); 629 } 630 if (x != null && !x.isZERO()) { // can happen 631 elem.put(i, x); 632 } 633 } 634 } 635 return new Product<C>(ring, elem); 636 } 637 638 639 /** 640 * Product quasi-remainder. 641 * @param S Product. 642 * @return this - (this/S)*S. 643 */ 644 public Product<C> remainder(Product<C> S) { 645 if (S == null) { 646 return this; //ring.getZERO(); 647 } 648 if (S.isZERO()) { 649 return this; 650 } 651 if (this.isZERO()) { 652 return this; 653 } 654 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 655 SortedMap<Integer, C> sel = S.val; 656 for (Integer i : val.keySet()) { 657 C y = sel.get(i); 658 if (y != null) { 659 C x = val.get(i); 660 x = x.remainder(y); 661 if (x != null && !x.isZERO()) { // can happen 662 elem.put(i, x); 663 } 664 } 665 } 666 return new Product<C>(ring, elem); 667 } 668 669 670 /** 671 * Product multiplication. 672 * @param S Product. 673 * @return this*S. 674 */ 675 public Product<C> multiply(Product<C> S) { 676 if (S == null) { 677 return ring.getZERO(); 678 } 679 if (S.isZERO()) { 680 return S; 681 } 682 if (this.isZERO()) { 683 return this; 684 } 685 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 686 SortedMap<Integer, C> sel = S.val; 687 for (Integer i : val.keySet()) { 688 C y = sel.get(i); 689 if (y != null) { 690 C x = val.get(i); 691 x = x.multiply(y); 692 if (x != null && !x.isZERO()) { 693 elem.put(i, x); 694 } 695 } 696 } 697 return new Product<C>(ring, elem); 698 } 699 700 701 /** 702 * Product multiply by coefficient. 703 * @param c coefficient. 704 * @return this*c. 705 */ 706 public Product<C> multiply(C c) { 707 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 708 for (Integer i : val.keySet()) { 709 C v = val.get(i).multiply(c); 710 if (v != null && !v.isZERO()) { 711 elem.put(i, v); 712 } 713 } 714 return new Product<C>(ring, elem); 715 } 716 717 718 /** 719 * Greatest common divisor. 720 * @param S other element. 721 * @return gcd(this,S). 722 */ 723 public Product<C> gcd(Product<C> S) { 724 if (S == null || S.isZERO()) { 725 return this; 726 } 727 if (this.isZERO()) { 728 return S; 729 } 730 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); // clone 731 SortedMap<Integer, C> sel = S.val; 732 for (Map.Entry<Integer, C> is : sel.entrySet()) { 733 Integer i = is.getKey(); 734 C x = elem.get(i); 735 C y = is.getValue(); //sel.get( i ); // assert y != null 736 if (x != null) { 737 x = x.gcd(y); 738 if (x != null && !x.isZERO()) { 739 elem.put(i, x); 740 } else { 741 elem.remove(i); 742 } 743 } else { 744 elem.put(i, y); 745 } 746 } 747 return new Product<C>(ring, elem); 748 } 749 750 751 /** 752 * Extended greatest common divisor. 753 * @param S other element. 754 * @return [ gcd(this,S), c1, c2 ] with c1*this + c2*b = gcd(this,S). 755 */ 756 @SuppressWarnings("unchecked") 757 public Product<C>[] egcd(Product<C> S) { 758 Product<C>[] ret = (Product<C>[]) new Product[3]; 759 ret[0] = null; 760 ret[1] = null; 761 ret[2] = null; 762 if (S == null || S.isZERO()) { 763 ret[0] = this; 764 return ret; 765 } 766 if (this.isZERO()) { 767 ret[0] = S; 768 return ret; 769 } 770 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); // clone 771 SortedMap<Integer, C> elem1 = this.idempotent().val; // init with 1 772 SortedMap<Integer, C> elem2 = new TreeMap<Integer, C>(); // zero 773 SortedMap<Integer, C> sel = S.val; 774 for (Map.Entry<Integer, C> is : sel.entrySet()) { 775 Integer i = is.getKey(); 776 C x = elem.get(i); 777 C y = is.getValue(); //sel.get( i ); // assert y != null 778 if (x != null) { 779 C[] g = x.egcd(y); 780 if (!g[0].isZERO()) { 781 elem.put(i, g[0]); 782 elem1.put(i, g[1]); 783 elem2.put(i, g[2]); 784 } else { 785 elem.remove(i); 786 } 787 } else { 788 elem.put(i, y); 789 elem2.put(i, ring.getFactory(i).getONE()); 790 } 791 } 792 ret[0] = new Product<C>(ring, elem); 793 ret[1] = new Product<C>(ring, elem1); 794 ret[2] = new Product<C>(ring, elem2); 795 return ret; 796 } 797 798}