001/* 002 * $Id: Local.java 4125 2012-08-19 19:05:22Z kredel $ 003 */ 004 005package edu.jas.poly; 006 007 008import org.apache.log4j.Logger; 009 010import edu.jas.structure.GcdRingElem; 011import edu.jas.structure.RingElem; 012 013 014/** 015 * Local element based on RingElem pairs. Objects of this class are (nearly) 016 * immutable. 017 * @author Heinz Kredel 018 * @fix Not jet working because of monic GBs. 019 */ 020public class Local<C extends RingElem<C>> implements RingElem<Local<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 * Clone this. 150 * @see java.lang.Object#clone() 151 */ 152 @Override 153 public Local<C> copy() { 154 return new Local<C>(ring, num, den, true); 155 } 156 157 158 /** 159 * Is Local zero. 160 * @return If this is 0 then true is returned, else false. 161 * @see edu.jas.structure.RingElem#isZERO() 162 */ 163 public boolean isZERO() { 164 return num.isZERO(); 165 } 166 167 168 /** 169 * Is Local one. 170 * @return If this is 1 then true is returned, else false. 171 * @see edu.jas.structure.RingElem#isONE() 172 */ 173 public boolean isONE() { 174 return num.equals(den); 175 } 176 177 178 /** 179 * Is Local unit. 180 * @return If this is a unit then true is returned, else false. 181 * @see edu.jas.structure.RingElem#isUnit() 182 */ 183 public boolean isUnit() { 184 if (isunit > 0) { 185 return true; 186 } 187 if (isunit == 0) { 188 return false; 189 } 190 // not jet known 191 if (num.isZERO()) { 192 isunit = 0; 193 return false; 194 } 195 C p = num.remainder(ring.ideal); 196 boolean u = (p != null && !p.isZERO()); 197 if (u) { 198 isunit = 1; 199 } else { 200 isunit = 0; 201 } 202 return (u); 203 } 204 205 206 /** 207 * Get the String representation as RingElem. 208 * @see java.lang.Object#toString() 209 */ 210 @Override 211 public String toString() { 212 return "Local[ " + num.toString() + " / " + den.toString() + " ]"; 213 } 214 215 216 /** 217 * Get a scripting compatible string representation. 218 * @return script compatible representation for this Element. 219 * @see edu.jas.structure.Element#toScript() 220 */ 221 //JAVA6only: @Override 222 public String toScript() { 223 // Python case 224 return "Local( " + num.toScript() + " , " + den.toScript() + " )"; 225 } 226 227 228 /** 229 * Get a scripting compatible string representation of the factory. 230 * @return script compatible representation for this ElemFactory. 231 * @see edu.jas.structure.Element#toScriptFactory() 232 */ 233 //JAVA6only: @Override 234 public String toScriptFactory() { 235 // Python case 236 return factory().toScript(); 237 } 238 239 240 /** 241 * Local comparison. 242 * @param b Local. 243 * @return sign(this-b). 244 */ 245 //JAVA6only: @Override 246 public int compareTo(Local<C> b) { 247 if (b == null || b.isZERO()) { 248 return this.signum(); 249 } 250 C r = num.multiply(b.den); 251 C s = den.multiply(b.num); 252 C x = r.subtract(s); 253 return x.signum(); 254 } 255 256 257 /** 258 * Comparison with any other object. 259 * @see java.lang.Object#equals(java.lang.Object) 260 */ 261 @SuppressWarnings("unchecked") 262 // not jet working 263 @Override 264 public boolean equals(Object b) { 265 if (!(b instanceof Local)) { 266 return false; 267 } 268 Local<C> a = null; 269 try { 270 a = (Local<C>) b; 271 } catch (ClassCastException e) { 272 } 273 if (a == null) { 274 return false; 275 } 276 return (0 == compareTo(a)); 277 } 278 279 280 /** 281 * Hash code for this local. 282 * @see java.lang.Object#hashCode() 283 */ 284 @Override 285 public int hashCode() { 286 int h; 287 h = ring.hashCode(); 288 h = 37 * h + num.hashCode(); 289 h = 37 * h + den.hashCode(); 290 return h; 291 } 292 293 294 /** 295 * Local absolute value. 296 * @return the absolute value of this. 297 * @see edu.jas.structure.RingElem#abs() 298 */ 299 public Local<C> abs() { 300 return new Local<C>(ring, num.abs(), den, true); 301 } 302 303 304 /** 305 * Local summation. 306 * @param S Local. 307 * @return this+S. 308 */ 309 public Local<C> sum(Local<C> S) { 310 if (S == null || S.isZERO()) { 311 return this; 312 } 313 C n = num.multiply(S.den); 314 n = n.sum(den.multiply(S.num)); 315 C d = den.multiply(S.den); 316 return new Local<C>(ring, n, d, false); 317 } 318 319 320 /** 321 * Local negate. 322 * @return -this. 323 * @see edu.jas.structure.RingElem#negate() 324 */ 325 public Local<C> negate() { 326 return new Local<C>(ring, num.negate(), den, true); 327 } 328 329 330 /** 331 * Local signum. 332 * @see edu.jas.structure.RingElem#signum() 333 * @return signum(this). 334 */ 335 public int signum() { 336 return num.signum(); 337 } 338 339 340 /** 341 * Local subtraction. 342 * @param S Local. 343 * @return this-S. 344 */ 345 public Local<C> subtract(Local<C> S) { 346 if (S == null || S.isZERO()) { 347 return this; 348 } 349 C n = num.multiply(S.den); 350 n = n.subtract(den.multiply(S.num)); 351 C d = den.multiply(S.den); 352 return new Local<C>(ring, n, d, false); 353 } 354 355 356 /** 357 * Local division. 358 * @param S Local. 359 * @return this/S. 360 */ 361 public Local<C> divide(Local<C> S) { 362 return multiply(S.inverse()); 363 } 364 365 366 /** 367 * Local inverse. 368 * @see edu.jas.structure.RingElem#inverse() 369 * @return S with S = 1/this if defined. 370 */ 371 public Local<C> inverse() { 372 if (isONE()) { 373 return this; 374 } 375 if (isUnit()) { 376 return new Local<C>(ring, den, num, true); 377 } 378 throw new ArithmeticException("element not invertible " + this); 379 } 380 381 382 /** 383 * Local remainder. 384 * @param S Local. 385 * @return this - (this/S)*S. 386 */ 387 public Local<C> remainder(Local<C> S) { 388 if (num.isZERO()) { 389 throw new ArithmeticException("element not invertible " + this); 390 } 391 if (S.isUnit()) { 392 return ring.getZERO(); 393 } else { 394 throw new UnsupportedOperationException("remainder not implemented" + S); 395 } 396 } 397 398 399 /** 400 * Local multiplication. 401 * @param S Local. 402 * @return this*S. 403 */ 404 public Local<C> multiply(Local<C> S) { 405 if (S == null || S.isZERO()) { 406 return S; 407 } 408 if (num.isZERO()) { 409 return this; 410 } 411 if (S.isONE()) { 412 return this; 413 } 414 if (this.isONE()) { 415 return S; 416 } 417 C n = num.multiply(S.num); 418 C d = den.multiply(S.den); 419 return new Local<C>(ring, n, d, false); 420 } 421 422 423 /** 424 * Greatest common divisor. <b>Note: </b>Not implemented, throws 425 * UnsupportedOperationException. 426 * @param b other element. 427 * @return gcd(this,b). 428 */ 429 public Local<C> gcd(Local<C> b) { 430 throw new UnsupportedOperationException("gcd not implemented " + this.getClass().getName()); 431 } 432 433 434 /** 435 * Extended greatest common divisor. <b>Note: </b>Not implemented, throws 436 * UnsupportedOperationException. 437 * @param b other element. 438 * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). 439 */ 440 public Local<C>[] egcd(Local<C> b) { 441 throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName()); 442 } 443 444}