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