001/* 002 * $Id: Product.java 5310 2015-10-25 18:35:31Z 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 @Override 217 public String toScript() { 218 // Python case 219 StringBuffer s = new StringBuffer("( "); 220 boolean first = true; 221 for (Map.Entry<Integer,C> me : val.entrySet()) { 222 Integer i = me.getKey(); 223 C v = me.getValue(); 224 if (first) { 225 first = false; 226 } else { 227 if (v.signum() < 0) { 228 s.append(" - "); 229 v = v.negate(); 230 } else { 231 s.append(" + "); 232 } 233 } 234 if (!v.isONE()) { 235 s.append(v.toScript() + "*"); 236 } 237 s.append("pg" + i); 238 } 239 s.append(" )"); 240 return s.toString(); 241 } 242 243 244 /** 245 * Get a scripting compatible string representation of the factory. 246 * @return script compatible representation for this ElemFactory. 247 * @see edu.jas.structure.Element#toScriptFactory() 248 */ 249 @Override 250 public String toScriptFactory() { 251 // Python case 252 return factory().toScript(); 253 } 254 255 256 /** 257 * Product comparison. 258 * @param b Product. 259 * @return sign(this-b). 260 */ 261 @Override 262 public int compareTo(Product<C> b) { 263 if (!ring.equals(b.ring)) { 264 logger.info("other ring " + b.ring); 265 throw new IllegalArgumentException("rings not comparable " + this); 266 } 267 SortedMap<Integer, C> v = b.val; 268 Iterator<Map.Entry<Integer, C>> ti = val.entrySet().iterator(); 269 Iterator<Map.Entry<Integer, C>> bi = v.entrySet().iterator(); 270 int s; 271 while (ti.hasNext() && bi.hasNext()) { 272 Map.Entry<Integer, C> te = ti.next(); 273 Map.Entry<Integer, C> be = bi.next(); 274 s = te.getKey().compareTo(be.getKey()); 275 if (s != 0) { 276 return s; 277 } 278 s = te.getValue().compareTo(be.getValue()); 279 if (s != 0) { 280 return s; 281 } 282 } 283 if (ti.hasNext()) { 284 return -1; 285 } 286 if (bi.hasNext()) { 287 return 1; 288 } 289 return 0; 290 } 291 292 293 /** 294 * Comparison with any other object. 295 * @see java.lang.Object#equals(java.lang.Object) 296 */ 297 @SuppressWarnings("unchecked") 298 @Override 299 public boolean equals(Object b) { 300 if (b == null) { 301 return false; 302 } 303 if (!(b instanceof Product)) { 304 return false; 305 } 306 Product<C> a = (Product<C>) b; 307 return (0 == compareTo(a)); 308 } 309 310 311 /** 312 * Hash code for this local. 313 * @see java.lang.Object#hashCode() 314 */ 315 @Override 316 public int hashCode() { 317 int h = ring.hashCode(); 318 h = 37 * h + val.hashCode(); 319 return h; 320 } 321 322 323 /** 324 * Product extend. Add new component j with value of component i. 325 * @param i from index. 326 * @param j to index. 327 * @return the extended value of this. 328 */ 329 public Product<C> extend(int i, int j) { 330 RingFactory<C> rf = ring.getFactory(j); 331 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); 332 C v = val.get(i); 333 C w = rf.copy(v); // valueOf 334 if (!w.isZERO()) { 335 elem.put(j, w); 336 } 337 return new Product<C>(ring, elem, isunit); 338 } 339 340 341 /** 342 * Product absolute value. 343 * @return the absolute value of this. 344 * @see edu.jas.structure.RingElem#abs() 345 */ 346 public Product<C> abs() { 347 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 348 for (Map.Entry<Integer,C> e : val.entrySet()) { 349 Integer i = e.getKey(); 350 C v = e.getValue().abs(); 351 elem.put(i, v); 352 } 353 return new Product<C>(ring, elem, isunit); 354 } 355 356 357 /** 358 * Product summation. 359 * @param S Product. 360 * @return this+S. 361 */ 362 public Product<C> sum(Product<C> S) { 363 if (S == null || S.isZERO()) { 364 return this; 365 } 366 if (this.isZERO()) { 367 return S; 368 } 369 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); // clone 370 SortedMap<Integer, C> sel = S.val; 371 for (Map.Entry<Integer, C> is : sel.entrySet()) { 372 Integer i = is.getKey(); 373 C x = elem.get(i); 374 C y = is.getValue(); //sel.get( i ); // assert y != null 375 if (x != null) { 376 x = x.sum(y); 377 if (!x.isZERO()) { 378 elem.put(i, x); 379 } else { 380 elem.remove(i); 381 } 382 } else { 383 elem.put(i, y); 384 } 385 } 386 return new Product<C>(ring, elem); 387 } 388 389 390 /** 391 * Product negate. 392 * @return -this. 393 * @see edu.jas.structure.RingElem#negate() 394 */ 395 public Product<C> negate() { 396 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 397 for (Map.Entry<Integer,C> me : val.entrySet()) { 398 Integer i = me.getKey(); 399 C v = me.getValue().negate(); 400 elem.put(i, v); 401 } 402 return new Product<C>(ring, elem, isunit); 403 } 404 405 406 /** 407 * Product signum. 408 * @see edu.jas.structure.RingElem#signum() 409 * @return signum of first non-zero component. 410 */ 411 public int signum() { 412 if (val.size() == 0) { 413 return 0; 414 } 415 C v = val.get(val.firstKey()); 416 return v.signum(); 417 } 418 419 420 /** 421 * Product subtraction. 422 * @param S Product. 423 * @return this-S. 424 */ 425 public Product<C> subtract(Product<C> S) { 426 return sum(S.negate()); 427 } 428 429 430 /** 431 * Product quasi-inverse. 432 * @see edu.jas.structure.RingElem#inverse() 433 * @return S with S = 1/this if defined. 434 */ 435 public Product<C> inverse() { 436 if (this.isZERO()) { 437 return this; 438 } 439 int isu = 0; 440 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 441 for (Map.Entry<Integer,C> me : val.entrySet()) { 442 Integer i = me.getKey(); 443 C x = me.getValue(); // 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 (Map.Entry<Integer,C> me : val.entrySet()) { 619 Integer i = me.getKey(); 620 C y = sel.get(i); 621 if (y != null) { 622 C x = me.getValue(); 623 try { 624 x = x.divide(y); 625 } catch (NotInvertibleException e) { 626 // should not happen any more 627 System.out.println("product divide error: x = " + x + ", y = " + y); 628 // could happen for e.g. ModInteger or AlgebraicNumber 629 x = null; //ring.getFactory(i).getZERO(); 630 } 631 if (x != null && !x.isZERO()) { // can happen 632 elem.put(i, x); 633 } 634 } 635 } 636 return new Product<C>(ring, elem); 637 } 638 639 640 /** 641 * Product quasi-remainder. 642 * @param S Product. 643 * @return this - (this/S)*S. 644 */ 645 public Product<C> remainder(Product<C> S) { 646 if (S == null) { 647 return this; //ring.getZERO(); 648 } 649 if (S.isZERO()) { 650 return this; 651 } 652 if (this.isZERO()) { 653 return this; 654 } 655 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 656 SortedMap<Integer, C> sel = S.val; 657 for (Map.Entry<Integer,C> me : val.entrySet()) { 658 Integer i = me.getKey(); 659 C y = sel.get(i); 660 if (y != null) { 661 C x = me.getValue(); 662 x = x.remainder(y); 663 if (x != null && !x.isZERO()) { // can happen 664 elem.put(i, x); 665 } 666 } 667 } 668 return new Product<C>(ring, elem); 669 } 670 671 672 /** 673 * Quotient and remainder by division of this by S. 674 * @param S a product 675 * @return [this/S, this - (this/S)*S]. 676 */ 677 public Product<C>[] quotientRemainder(Product<C> S) { 678 return new Product[] { divide(S), remainder(S) }; 679 } 680 681 682 /** 683 * Product multiplication. 684 * @param S Product. 685 * @return this*S. 686 */ 687 public Product<C> multiply(Product<C> S) { 688 if (S == null) { 689 return ring.getZERO(); 690 } 691 if (S.isZERO()) { 692 return S; 693 } 694 if (this.isZERO()) { 695 return this; 696 } 697 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 698 SortedMap<Integer, C> sel = S.val; 699 for (Map.Entry<Integer,C> me : val.entrySet()) { 700 Integer i = me.getKey(); 701 C y = sel.get(i); 702 if (y != null) { 703 C x = me.getValue(); 704 x = x.multiply(y); 705 if (x != null && !x.isZERO()) { 706 elem.put(i, x); 707 } 708 } 709 } 710 return new Product<C>(ring, elem); 711 } 712 713 714 /** 715 * Product multiply by coefficient. 716 * @param c coefficient. 717 * @return this*c. 718 */ 719 public Product<C> multiply(C c) { 720 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(); 721 for (Map.Entry<Integer,C> me : val.entrySet()) { 722 Integer i = me.getKey(); 723 C v = me.getValue().multiply(c); 724 if (v != null && !v.isZERO()) { 725 elem.put(i, v); 726 } 727 } 728 return new Product<C>(ring, elem); 729 } 730 731 732 /** 733 * Greatest common divisor. 734 * @param S other element. 735 * @return gcd(this,S). 736 */ 737 public Product<C> gcd(Product<C> S) { 738 if (S == null || S.isZERO()) { 739 return this; 740 } 741 if (this.isZERO()) { 742 return S; 743 } 744 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); // clone 745 SortedMap<Integer, C> sel = S.val; 746 for (Map.Entry<Integer, C> is : sel.entrySet()) { 747 Integer i = is.getKey(); 748 C x = elem.get(i); 749 C y = is.getValue(); //sel.get( i ); // assert y != null 750 if (x != null) { 751 x = x.gcd(y); 752 if (x != null && !x.isZERO()) { 753 elem.put(i, x); 754 } else { 755 elem.remove(i); 756 } 757 } else { 758 elem.put(i, y); 759 } 760 } 761 return new Product<C>(ring, elem); 762 } 763 764 765 /** 766 * Extended greatest common divisor. 767 * @param S other element. 768 * @return [ gcd(this,S), c1, c2 ] with c1*this + c2*b = gcd(this,S). 769 */ 770 @SuppressWarnings("cast") 771 public Product<C>[] egcd(Product<C> S) { 772 Product<C>[] ret = (Product<C>[]) new Product[3]; 773 ret[0] = null; 774 ret[1] = null; 775 ret[2] = null; 776 if (S == null || S.isZERO()) { 777 ret[0] = this; 778 return ret; 779 } 780 if (this.isZERO()) { 781 ret[0] = S; 782 return ret; 783 } 784 SortedMap<Integer, C> elem = new TreeMap<Integer, C>(val); // clone 785 SortedMap<Integer, C> elem1 = this.idempotent().val; // init with 1 786 SortedMap<Integer, C> elem2 = new TreeMap<Integer, C>(); // zero 787 SortedMap<Integer, C> sel = S.val; 788 for (Map.Entry<Integer, C> is : sel.entrySet()) { 789 Integer i = is.getKey(); 790 C x = elem.get(i); 791 C y = is.getValue(); //sel.get( i ); // assert y != null 792 if (x != null) { 793 C[] g = x.egcd(y); 794 if (!g[0].isZERO()) { 795 elem.put(i, g[0]); 796 elem1.put(i, g[1]); 797 elem2.put(i, g[2]); 798 } else { 799 elem.remove(i); 800 } 801 } else { 802 elem.put(i, y); 803 elem2.put(i, ring.getFactory(i).getONE()); 804 } 805 } 806 ret[0] = new Product<C>(ring, elem); 807 ret[1] = new Product<C>(ring, elem1); 808 ret[2] = new Product<C>(ring, elem2); 809 return ret; 810 } 811 812}