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