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