001/* 002 * $Id: SolvableQuotient.java 5826 2018-05-13 15:29:53Z kredel $ 003 */ 004 005package edu.jas.fd; 006 007 008import java.util.Arrays; 009 010import org.apache.log4j.Logger; 011 012import edu.jas.kern.PrettyPrint; 013import edu.jas.poly.ExpVector; 014import edu.jas.poly.GenPolynomial; 015import edu.jas.poly.GenSolvablePolynomial; 016import edu.jas.structure.GcdRingElem; 017import edu.jas.structure.QuotPair; 018 019 020/** 021 * SolvableQuotient, that is a (left) rational function, based on 022 * GenSolvablePolynomial with RingElem interface. Objects of this class are 023 * immutable. 024 * @author Heinz Kredel 025 */ 026public class SolvableQuotient<C extends GcdRingElem<C>> 027 implements GcdRingElem<SolvableQuotient<C>>, QuotPair<GenPolynomial<C>> { 028 // should be QuotPair<GenSolvablePolynomial<C> 029 030 031 private static final Logger logger = Logger.getLogger(SolvableQuotient.class); 032 033 034 private static final boolean debug = logger.isDebugEnabled(); 035 036 037 /** 038 * SolvableQuotient class factory data structure. 039 */ 040 public final SolvableQuotientRing<C> ring; 041 042 043 /** 044 * Numerator part of the element data structure. 045 */ 046 public final GenSolvablePolynomial<C> num; 047 048 049 /** 050 * Denominator part of the element data structure. 051 */ 052 public final GenSolvablePolynomial<C> den; 053 054 055 /** 056 * The constructor creates a SolvableQuotient object from a ring factory. 057 * @param r ring factory. 058 */ 059 public SolvableQuotient(SolvableQuotientRing<C> r) { 060 this(r, r.ring.getZERO()); 061 } 062 063 064 /** 065 * The constructor creates a SolvableQuotient object from a ring factory and 066 * a numerator polynomial. The denominator is assumed to be 1. 067 * @param r ring factory. 068 * @param n numerator solvable polynomial. 069 */ 070 public SolvableQuotient(SolvableQuotientRing<C> r, GenSolvablePolynomial<C> n) { 071 this(r, n, r.ring.getONE(), true); 072 } 073 074 075 /** 076 * The constructor creates a SolvableQuotient object from a ring factory and 077 * a numerator and denominator solvable polynomial. 078 * @param r ring factory. 079 * @param n numerator polynomial. 080 * @param d denominator polynomial. 081 */ 082 public SolvableQuotient(SolvableQuotientRing<C> r, GenSolvablePolynomial<C> n, 083 GenSolvablePolynomial<C> d) { 084 this(r, n, d, false); 085 } 086 087 088 /** 089 * The constructor creates a SolvableQuotient object from a ring factory and 090 * a numerator and denominator polynomial. 091 * @param r ring factory. 092 * @param n numerator polynomial. 093 * @param d denominator polynomial. 094 * @param isred <em>unused at the moment</em>. 095 */ 096 protected SolvableQuotient(SolvableQuotientRing<C> r, GenSolvablePolynomial<C> n, 097 GenSolvablePolynomial<C> d, boolean isred) { 098 if (d == null || d.isZERO()) { 099 throw new IllegalArgumentException("denominator may not be zero"); 100 } 101 ring = r; 102 if (d.signum() < 0) { 103 n = (GenSolvablePolynomial<C>) n.negate(); 104 d = (GenSolvablePolynomial<C>) d.negate(); 105 } 106 if (isred) { 107 num = n; 108 den = d; 109 return; 110 } 111 C lc = d.leadingBaseCoefficient(); 112 if (!lc.isONE() && lc.isUnit()) { 113 lc = lc.inverse(); 114 n = n.multiply(lc); 115 d = d.multiply(lc); 116 } 117 if (n.compareTo(d) == 0) { 118 num = ring.ring.getONE(); 119 den = ring.ring.getONE(); 120 return; 121 } 122 if (n.negate().compareTo(d) == 0) { 123 num = (GenSolvablePolynomial<C>) ring.ring.getONE().negate(); 124 den = ring.ring.getONE(); 125 return; 126 } 127 if (n.isZERO()) { 128 num = n; 129 den = ring.ring.getONE(); 130 return; 131 } 132 //if (n.isONE() || d.isONE()) { 133 if (n.isConstant() || d.isConstant()) { 134 num = n; 135 den = d; 136 return; 137 } 138 // must reduce to lowest terms 139 // not perfect, TODO 140 //GenSolvablePolynomial<C>[] gcd = PolyModUtil.<C> syzGcdCofactors(r.ring, n, d); 141 GenSolvablePolynomial<C>[] gcd = FDUtil.<C> leftGcdCofactors(r.ring, n, d); 142 if (!gcd[0].isONE()) { 143 logger.info("constructor: gcd = " + Arrays.toString(gcd)); // + ", " + n + ", " +d); 144 n = gcd[1]; 145 d = gcd[2]; 146 } 147 gcd = FDUtil.<C> rightGcdCofactors(r.ring, n, d); 148 if (!gcd[0].isONE()) { 149 logger.info("constructor: gcd = " + Arrays.toString(gcd)); // + ", " + n + ", " +d); 150 n = gcd[1]; 151 d = gcd[2]; 152 } 153 // not perfect, TODO 154 GenSolvablePolynomial<C>[] simp = ring.engine.leftSimplifier(n, d); 155 logger.info("simp: " + Arrays.toString(simp) + ", " + n + ", " + d); 156 num = simp[0]; 157 den = simp[1]; 158 } 159 160 161 /** 162 * Get the corresponding element factory. 163 * @return factory for this Element. 164 * @see edu.jas.structure.Element#factory() 165 */ 166 public SolvableQuotientRing<C> factory() { 167 return ring; 168 } 169 170 171 /** 172 * Numerator. 173 * @see edu.jas.structure.QuotPair#numerator() 174 */ 175 public GenSolvablePolynomial<C> numerator() { 176 return num; 177 } 178 179 180 /** 181 * Denominator. 182 * @see edu.jas.structure.QuotPair#denominator() 183 */ 184 public GenSolvablePolynomial<C> denominator() { 185 return den; 186 } 187 188 189 /** 190 * Clone this. 191 * @see java.lang.Object#clone() 192 */ 193 @Override 194 public SolvableQuotient<C> copy() { 195 return new SolvableQuotient<C>(ring, num, den, true); 196 } 197 198 199 /** 200 * Is SolvableQuotient zero. 201 * @return If this is 0 then true is returned, else false. 202 * @see edu.jas.structure.RingElem#isZERO() 203 */ 204 public boolean isZERO() { 205 return num.isZERO(); 206 } 207 208 209 /** 210 * Is SolvableQuotient one. 211 * @return If this is 1 then true is returned, else false. 212 * @see edu.jas.structure.RingElem#isONE() 213 */ 214 public boolean isONE() { 215 return num.compareTo(den) == 0; 216 } 217 218 219 /** 220 * Is SolvableQuotient a unit. 221 * @return If this is a unit then true is returned, else false. 222 * @see edu.jas.structure.RingElem#isUnit() 223 */ 224 public boolean isUnit() { 225 if (num.isZERO()) { 226 return false; 227 } 228 return true; 229 } 230 231 232 /** 233 * Is Qoutient a constant. 234 * @return true, if this has constant numerator and denominator, else false. 235 */ 236 public boolean isConstant() { 237 return num.isConstant() && den.isConstant(); 238 } 239 240 241 /** 242 * Get the String representation as RingElem. 243 * @see java.lang.Object#toString() 244 */ 245 @Override 246 public String toString() { 247 if (PrettyPrint.isTrue()) { 248 String s = "{ " + num.toString(ring.ring.getVars()); 249 if (!den.isONE()) { 250 s += " | " + den.toString(ring.ring.getVars()); 251 } 252 return s + " }"; 253 } 254 return "SolvableQuotient[ " + num.toString() + " | " + den.toString() + " ]"; 255 } 256 257 258 /** 259 * Get a scripting compatible string representation. 260 * @return script compatible representation for this Element. 261 * @see edu.jas.structure.Element#toScript() 262 */ 263 @Override 264 public String toScript() { 265 // any scripting case 266 if (den.isONE()) { 267 return num.toScript(); 268 } 269 return num.toScript() + " / " + den.toScript(); 270 } 271 272 273 /** 274 * Get a scripting compatible string representation of the factory. 275 * @return script compatible representation for this ElemFactory. 276 * @see edu.jas.structure.Element#toScriptFactory() 277 */ 278 @Override 279 public String toScriptFactory() { 280 return factory().toScript(); 281 } 282 283 284 /** 285 * SolvableQuotient comparison. 286 * @param b SolvableQuotient. 287 * @return sign(this-b). 288 */ 289 @Override 290 public int compareTo(SolvableQuotient<C> b) { 291 if (b == null || b.isZERO()) { 292 return this.signum(); 293 } 294 if (this.isZERO()) { 295 return -b.signum(); 296 } 297 // assume sign(den,b.den) > 0 298 int s1 = num.signum(); 299 int s2 = b.num.signum(); 300 int t = (s1 - s2) / 2; 301 if (t != 0) { 302 return t; 303 } 304 if (den.compareTo(b.den) == 0) { 305 return num.compareTo(b.num); 306 } 307 GenSolvablePolynomial<C> r, s; 308 // if (den.isONE()) { 309 // r = b.den.multiply(num); 310 // s = b.num; 311 // return r.compareTo(s); 312 // } 313 // if (b.den.isONE()) { 314 // r = num; 315 // s = den.multiply(b.num); 316 // return r.compareTo(s); 317 // } 318 GenSolvablePolynomial<C>[] oc = ring.engine.leftOreCond(den, b.den); 319 if (debug) { 320 System.out.println("oc[0] den =<>= oc[1] b.den: (" + oc[0] + ") (" + den + ") = (" + oc[1] + ") (" 321 + b.den + ")"); 322 } 323 r = oc[0].multiply(num); 324 s = oc[1].multiply(b.num); 325 //System.out.println("r = " + r); 326 //System.out.println("s = " + s); 327 return r.compareTo(s); 328 } 329 330 331 /** 332 * Comparison with any other object. 333 * @see java.lang.Object#equals(java.lang.Object) 334 */ 335 @SuppressWarnings("unchecked") 336 @Override 337 public boolean equals(Object b) { 338 if (b == null) { 339 return false; 340 } 341 if (!(b instanceof SolvableQuotient)) { 342 return false; 343 } 344 SolvableQuotient<C> a = (SolvableQuotient<C>) b; 345 if (num.equals(a.num) && den.equals(a.den)) { // short cut 346 return true; 347 } 348 return compareTo(a) == 0; 349 } 350 351 352 /** 353 * Hash code for this element. 354 * @see java.lang.Object#hashCode() 355 */ 356 @Override 357 public int hashCode() { 358 int h; 359 h = ring.hashCode(); 360 h = 37 * h + num.hashCode(); 361 h = 37 * h + den.hashCode(); 362 return h; 363 } 364 365 366 /** 367 * SolvableQuotient right fraction. <b>Note:</b> It is not possible to 368 * distinguish right from left fractions in the current implementation. So 369 * it is not possible to compute with right fractions. 370 * @return SolvableQuotient(a,b), where den<sup>-1</sup> num = a b 371 * <sup>-1</sup> 372 */ 373 public SolvableQuotient<C> rightFraction() { 374 if (isZERO() || isONE()) { 375 return this; 376 } 377 GenSolvablePolynomial<C>[] oc = ring.engine.rightOreCond(num, den); 378 return new SolvableQuotient<C>(ring, oc[1], oc[0], true); // reversed, true is wrong but okay 379 } 380 381 382 /** 383 * Test if SolvableQuotient right fraction. <b>Note:</b> It is not possible 384 * to distinguish right from left fractions in the current implementation. 385 * So it is not possible to compute with right fractions. 386 * @param s = SolvableQuotient(a,b) 387 * @return true if s is a right fraction of this, i.e. den<sup>-1</sup> num 388 * = a b<sup>-1</sup> 389 */ 390 public boolean isRightFraction(SolvableQuotient<C> s) { 391 if (isZERO()) { 392 return s.isZERO(); 393 } 394 if (isONE()) { 395 return s.isONE(); 396 } 397 GenSolvablePolynomial<C> x = den.multiply(s.num); 398 GenSolvablePolynomial<C> y = num.multiply(s.den); 399 return x.compareTo(y) == 0; 400 } 401 402 403 /** 404 * SolvableQuotient absolute value. 405 * @return the absolute value of this. 406 * @see edu.jas.structure.RingElem#abs() 407 */ 408 public SolvableQuotient<C> abs() { 409 return new SolvableQuotient<C>(ring, (GenSolvablePolynomial<C>) num.abs(), den, true); 410 } 411 412 413 /** 414 * SolvableQuotient summation. 415 * @param S SolvableQuotient. 416 * @return this+S. 417 */ 418 public SolvableQuotient<C> sum(SolvableQuotient<C> S) { 419 if (S == null || S.isZERO()) { 420 return this; 421 } 422 if (this.isZERO()) { 423 return S; 424 } 425 GenSolvablePolynomial<C> n, d, n1, n2; 426 if (den.isONE() && S.den.isONE()) { 427 n = (GenSolvablePolynomial<C>) num.sum(S.num); 428 return new SolvableQuotient<C>(ring, n, den, true); 429 } 430 /* wrong: 431 if (den.isONE()) { 432 n = S.den.multiply(num); 433 n = (GenSolvablePolynomial<C>) n.sum(S.num); 434 return new SolvableQuotient<C>(ring, n, S.den, false); 435 } 436 if (S.den.isONE()) { 437 n = den.multiply(S.num); 438 n = (GenSolvablePolynomial<C>) n.sum(num); 439 return new SolvableQuotient<C>(ring, n, den, false); 440 } 441 */ 442 if (den.compareTo(S.den) == 0) { // correct ? 443 //d = den.multiply(den); 444 //n1 = den.multiply(S.num); 445 //n2 = S.den.multiply(num); 446 n = (GenSolvablePolynomial<C>) num.sum(S.num); 447 return new SolvableQuotient<C>(ring, n, den, false); 448 } 449 // general case 450 GenSolvablePolynomial<C>[] oc = ring.engine.leftOreCond(den, S.den); 451 if (debug) { 452 System.out.println("oc[0] den =sum= oc[1] S.den: (" + oc[0] + ") (" + den + ") = (" + oc[1] 453 + ") (" + S.den + ")"); 454 } 455 d = oc[0].multiply(den); 456 n1 = oc[0].multiply(num); 457 n2 = oc[1].multiply(S.num); 458 n = (GenSolvablePolynomial<C>) n1.sum(n2); 459 //System.out.println("n = " + n); 460 //System.out.println("d = " + d); 461 return new SolvableQuotient<C>(ring, n, d, false); 462 } 463 464 465 /** 466 * SolvableQuotient negate. 467 * @return -this. 468 * @see edu.jas.structure.RingElem#negate() 469 */ 470 public SolvableQuotient<C> negate() { 471 return new SolvableQuotient<C>(ring, (GenSolvablePolynomial<C>) num.negate(), den, true); 472 } 473 474 475 /** 476 * SolvableQuotient signum. 477 * @see edu.jas.structure.RingElem#signum() 478 * @return signum(this). 479 */ 480 public int signum() { 481 // assume sign(den) > 0 482 return num.signum(); 483 } 484 485 486 /** 487 * SolvableQuotient subtraction. 488 * @param S SolvableQuotient. 489 * @return this-S. 490 */ 491 public SolvableQuotient<C> subtract(SolvableQuotient<C> S) { 492 return sum(S.negate()); 493 } 494 495 496 /** 497 * SolvableQuotient division. 498 * @param S SolvableQuotient. 499 * @return this/S. 500 */ 501 public SolvableQuotient<C> divide(SolvableQuotient<C> S) { 502 return multiply(S.inverse()); 503 } 504 505 506 /** 507 * SolvableQuotient inverse. 508 * @see edu.jas.structure.RingElem#inverse() 509 * @return S with S = 1/this. 510 */ 511 public SolvableQuotient<C> inverse() { 512 if (num.isZERO()) { 513 throw new ArithmeticException("element not invertible " + this); 514 } 515 return new SolvableQuotient<C>(ring, den, num, true); 516 } 517 518 519 /** 520 * SolvableQuotient remainder. 521 * @param S SolvableQuotient. 522 * @return this - (this/S)*S. 523 */ 524 public SolvableQuotient<C> remainder(SolvableQuotient<C> S) { 525 if (S.isZERO()) { 526 throw new ArithmeticException("element not invertible " + S); 527 } 528 return ring.getZERO(); 529 } 530 531 532 /** 533 * Quotient and remainder by division of this by S. 534 * @param S a SolvableQuotient 535 * @return [this/S, this - (this/S)*S]. 536 */ 537 @SuppressWarnings("unchecked") 538 public SolvableQuotient<C>[] quotientRemainder(SolvableQuotient<C> S) { 539 return new SolvableQuotient[] { divide(S), remainder(S) }; 540 } 541 542 543 /** 544 * SolvableQuotient multiplication. 545 * @param S SolvableQuotient. 546 * @return this*S. 547 */ 548 public SolvableQuotient<C> multiply(SolvableQuotient<C> S) { 549 if (S == null || S.isZERO()) { 550 return S; 551 } 552 if (num.isZERO()) { 553 return this; 554 } 555 if (S.isONE()) { 556 return this; 557 } 558 if (this.isONE()) { 559 return S; 560 } 561 GenSolvablePolynomial<C> n, d; 562 if (den.isONE() && S.den.isONE()) { 563 n = num.multiply(S.num); 564 return new SolvableQuotient<C>(ring, n, den, true); 565 } 566 /* wrong: 567 if (den.isONE()) { 568 d = S.den; 569 n = num.multiply(S.num); 570 return new SolvableQuotient<C>(ring, n, d, false); 571 } 572 if (S.den.isONE()) { 573 d = den; 574 n = num.multiply(S.num); 575 return new SolvableQuotient<C>(ring, n, d, false); 576 } 577 */ 578 // if ( den.compareTo(S.den) == 0 ) { // not correct ? 579 // d = den.multiply(den); 580 // n = num.multiply(S.num); 581 // return new SolvableQuotient<C>(ring, n, d, false); 582 // } 583 GenSolvablePolynomial<C>[] oc = ring.engine.leftOreCond(num, S.den); 584 n = oc[1].multiply(S.num); 585 d = oc[0].multiply(den); 586 if (debug) { 587 System.out.println("oc[0] num =mult= oc[1] S.den: (" + oc[0] + ") (" + num + ") = (" + oc[1] 588 + ") (" + S.den + ")"); 589 } 590 return new SolvableQuotient<C>(ring, n, d, false); 591 } 592 593 594 /** 595 * SolvableQuotient multiplication by GenSolvablePolynomial. 596 * @param b GenSolvablePolynomial<C>. 597 * @return this*b. 598 */ 599 public SolvableQuotient<C> multiply(GenSolvablePolynomial<C> b) { 600 if (b == null || b.isZERO()) { 601 return ring.getZERO(); 602 } 603 if (num.isZERO()) { 604 return this; 605 } 606 if (b.isONE()) { 607 return this; 608 } 609 GenSolvablePolynomial<C> n = num.multiply(b); 610 return new SolvableQuotient<C>(ring, n, den, false); 611 } 612 613 614 /** 615 * SolvableQuotient multiplication by coefficient. 616 * @param b coefficient. 617 * @return this*b. 618 */ 619 public SolvableQuotient<C> multiply(C b) { 620 if (b == null || b.isZERO()) { 621 return ring.getZERO(); 622 } 623 if (num.isZERO()) { 624 return this; 625 } 626 if (b.isONE()) { 627 return this; 628 } 629 GenSolvablePolynomial<C> n = num.multiply(b); 630 return new SolvableQuotient<C>(ring, n, den, false); 631 } 632 633 634 /** 635 * SolvableQuotient multiplication by exponent. 636 * @param e exponent vector. 637 * @return this*b. 638 */ 639 public SolvableQuotient<C> multiply(ExpVector e) { 640 if (e == null || e.isZERO()) { 641 return this; 642 } 643 if (num.isZERO()) { 644 return this; 645 } 646 GenSolvablePolynomial<C> n = num.multiply(e); 647 return new SolvableQuotient<C>(ring, n, den, false); 648 } 649 650 651 /** 652 * SolvableQuotient monic. 653 * @return this with monic value part. 654 */ 655 public SolvableQuotient<C> monic() { 656 if (num.isZERO()) { 657 return this; 658 } 659 C lbc = num.leadingBaseCoefficient(); 660 if (!lbc.isUnit()) { 661 return this; 662 } 663 lbc = lbc.inverse(); 664 //lbc = lbc.abs(); 665 GenSolvablePolynomial<C> n = num.multiply(lbc); 666 //GenSolvablePolynomial<C> d = (GenSolvablePolynomial<C>) den.multiply(lbc); 667 return new SolvableQuotient<C>(ring, n, den, true); 668 } 669 670 671 /** 672 * Greatest common divisor. 673 * @param b other element. 674 * @return gcd(this,b). 675 */ 676 public SolvableQuotient<C> gcd(SolvableQuotient<C> b) { 677 if (b == null || b.isZERO()) { 678 return this; 679 } 680 if (this.isZERO()) { 681 return b; 682 } 683 if (this.equals(b)) { 684 return this; 685 } 686 return ring.getONE(); 687 } 688 689 690 /** 691 * Extended greatest common divisor. 692 * @param b other element. 693 * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). 694 */ 695 @SuppressWarnings("unchecked") 696 public SolvableQuotient<C>[] egcd(SolvableQuotient<C> b) { 697 @SuppressWarnings("cast") 698 SolvableQuotient<C>[] ret = (SolvableQuotient<C>[]) new SolvableQuotient[3]; 699 ret[0] = null; 700 ret[1] = null; 701 ret[2] = null; 702 if (b == null || b.isZERO()) { 703 ret[0] = this; 704 return ret; 705 } 706 if (this.isZERO()) { 707 ret[0] = b; 708 return ret; 709 } 710 GenSolvablePolynomial<C> two = ring.ring.fromInteger(2); 711 ret[0] = ring.getONE(); 712 ret[1] = (this.multiply(two)).inverse(); 713 ret[2] = (b.multiply(two)).inverse(); 714 return ret; 715 } 716 717}