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