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