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