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