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