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