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