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