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.NotInvertibleException; 014import edu.jas.structure.RingElem; 015 016 017/** 018 * Residue element based on RingElem residue. Objects of this class are (nearly) 019 * immutable. 020 * @author Heinz Kredel 021 */ 022public class Residue<C extends RingElem<C>> implements RingElem<Residue<C>> { 023 024 025 private static final Logger logger = LogManager.getLogger(Residue.class); 026 027 028 private static final boolean debug = logger.isDebugEnabled(); 029 030 031 /** 032 * Residue class factory data structure. 033 */ 034 protected final ResidueRing<C> ring; 035 036 037 /** 038 * Value part of the element data structure. 039 */ 040 protected final C val; 041 042 043 /** 044 * Flag to remember if this residue element is a unit. -1 is unknown, 1 is 045 * unit, 0 not a unit. 046 */ 047 protected int isunit = -1; // initially unknown 048 049 050 /** 051 * The constructor creates a Residue object from a ring factory. 052 * @param r ring factory. 053 */ 054 public Residue(ResidueRing<C> r) { 055 this(r, r.ring.getZERO(), 0); 056 } 057 058 059 /** 060 * The constructor creates a Residue object from a ring factory and a ring 061 * element. 062 * @param r ring factory. 063 * @param a ring element. 064 */ 065 public Residue(ResidueRing<C> r, C a) { 066 this(r, a, -1); 067 } 068 069 070 /** 071 * The constructor creates a Residue object from a ring factory, a ring 072 * element and an indicator if a is a unit. 073 * @param r ring factory. 074 * @param a ring element. 075 * @param u isunit indicator, -1, 0, 1. 076 */ 077 public Residue(ResidueRing<C> r, C a, int u) { 078 ring = r; 079 C v = a.remainder(ring.modul); 080 if (v.signum() < 0) { 081 v = v.sum(ring.modul); 082 } 083 val = v; 084 if (u == 0 || u == 1) { 085 isunit = u; 086 return; 087 } 088 if (val.isZERO()) { 089 isunit = 0; 090 return; 091 } 092 if (val.isUnit()) { 093 isunit = 1; 094 //} else { // not possible 095 //isunit = 0; 096 } 097 isunit = -1; 098 } 099 100 101 /** 102 * Get the corresponding element factory. 103 * @return factory for this Element. 104 * @see edu.jas.structure.Element#factory() 105 */ 106 public ResidueRing<C> factory() { 107 return ring; 108 } 109 110 111 /** 112 * Copy this. 113 * @see edu.jas.structure.Element#copy() 114 */ 115 @Override 116 public Residue<C> copy() { 117 return new Residue<C>(ring, val); 118 } 119 120 121 /** 122 * Is Residue zero. 123 * @return If this is 0 then true is returned, else false. 124 * @see edu.jas.structure.RingElem#isZERO() 125 */ 126 public boolean isZERO() { 127 return val.equals(ring.ring.getZERO()); 128 } 129 130 131 /** 132 * Is Residue one. 133 * @return If this is 1 then true is returned, else false. 134 * @see edu.jas.structure.RingElem#isONE() 135 */ 136 public boolean isONE() { 137 return val.equals(ring.ring.getONE()); 138 } 139 140 141 /** 142 * Is Residue unit. 143 * @return If this is a unit then true is returned, else false. 144 * @see edu.jas.structure.RingElem#isUnit() 145 */ 146 @SuppressWarnings("unchecked") 147 public boolean isUnit() { 148 if (isunit == 1) { 149 return true; 150 } 151 if (isunit == 0) { 152 return false; 153 } 154 // val.isUnit() already tested 155 // not jet known 156 if (val instanceof GcdRingElem && ring.modul instanceof GcdRingElem) { 157 GcdRingElem v = (GcdRingElem) val; 158 GcdRingElem m = (GcdRingElem) ring.modul; 159 C gcd = (C) v.gcd(m); 160 if (debug) { 161 logger.info("gcd = {}", gcd); 162 } 163 boolean u = gcd.isONE(); 164 if (u) { 165 isunit = 1; 166 } else { 167 isunit = 0; 168 } 169 return u; 170 } 171 // still unknown 172 return false; 173 } 174 175 176 /** 177 * Get the String representation as RingElem. 178 * @see java.lang.Object#toString() 179 */ 180 @Override 181 public String toString() { 182 if (PrettyPrint.isTrue()) { 183 String s = "{ " + val.toString() + " }"; 184 return s; 185 } 186 return "Residue[ " + val.toString() + " mod " + ring.toString() + " ]"; 187 } 188 189 190 /** 191 * Get a scripting compatible string representation. 192 * @return script compatible representation for this Element. 193 * @see edu.jas.structure.Element#toScript() 194 */ 195 @Override 196 public String toScript() { 197 // Python case 198 return "Residue( " + val.toScript() + " , " + ring.toScript() + " )"; 199 } 200 201 202 /** 203 * Get a scripting compatible string representation of the factory. 204 * @return script compatible representation for this ElemFactory. 205 * @see edu.jas.structure.Element#toScriptFactory() 206 */ 207 @Override 208 public String toScriptFactory() { 209 // Python case 210 return factory().toScript(); 211 } 212 213 214 /** 215 * Residue comparison. 216 * @param b Residue. 217 * @return sign(this-b), 0 means that this and b are equivalent in this 218 * residue class ring. 219 */ 220 @Override 221 public int compareTo(Residue<C> b) { 222 C v = b.val; 223 if (!ring.equals(b.ring)) { 224 v = v.remainder(ring.modul); 225 } 226 return val.compareTo(v); 227 } 228 229 230 /** 231 * Comparison with any other object. 232 * @see java.lang.Object#equals(java.lang.Object) 233 * @return true means that this and b are equivalent in this residue class 234 * ring. 235 */ 236 @Override 237 @SuppressWarnings("unchecked") 238 public boolean equals(Object b) { 239 if (b == null) { 240 return false; 241 } 242 if (!(b instanceof Residue)) { 243 return false; 244 } 245 Residue<C> a = (Residue<C>) b; 246 return (0 == compareTo(a)); 247 } 248 249 250 /** 251 * Hash code for this local. 252 * @see java.lang.Object#hashCode() 253 */ 254 @Override 255 public int hashCode() { 256 int h; 257 h = ring.hashCode(); 258 h = 37 * h + val.hashCode(); 259 return h; 260 } 261 262 263 /** 264 * Residue absolute value. 265 * @return the absolute value of this. 266 * @see edu.jas.structure.RingElem#abs() 267 */ 268 public Residue<C> abs() { 269 return new Residue<C>(ring, val.abs()); 270 } 271 272 273 /** 274 * Residue summation. 275 * @param S Residue. 276 * @return this+S. 277 */ 278 public Residue<C> sum(Residue<C> S) { 279 return new Residue<C>(ring, val.sum(S.val)); 280 } 281 282 283 /** 284 * Residue negate. 285 * @return -this. 286 * @see edu.jas.structure.RingElem#negate() 287 */ 288 public Residue<C> negate() { 289 return new Residue<C>(ring, val.negate()); 290 } 291 292 293 /** 294 * Residue signum. 295 * @see edu.jas.structure.RingElem#signum() 296 * @return signum(this). 297 */ 298 public int signum() { 299 return val.signum(); 300 } 301 302 303 /** 304 * Residue subtraction. 305 * @param S Residue. 306 * @return this-S. 307 */ 308 public Residue<C> subtract(Residue<C> S) { 309 return new Residue<C>(ring, val.subtract(S.val)); 310 } 311 312 313 /** 314 * Residue division. 315 * @param S Residue. 316 * @return this/S. 317 */ 318 public Residue<C> divide(Residue<C> S) { 319 return multiply(S.inverse()); 320 } 321 322 323 /** 324 * Residue inverse. 325 * @see edu.jas.structure.RingElem#inverse() 326 * @return S with S = 1/this if defined. 327 */ 328 @SuppressWarnings("unchecked") 329 public Residue<C> inverse() { 330 if (isunit == 0) { 331 throw new NotInvertibleException("element not invertible (0) " + this); 332 } 333 if (val instanceof GcdRingElem && ring.modul instanceof GcdRingElem) { 334 GcdRingElem v = (GcdRingElem) val; 335 GcdRingElem m = (GcdRingElem) ring.modul; 336 C[] egcd = (C[]) v.egcd(m); 337 //System.out.println("v = " + v + ", m = " + m + ", e[0] = " + egcd[0] + ", e[1] = " + egcd[1]); 338 if (debug) { 339 logger.info("egcd = {}, f = {}", egcd[0], egcd[1]); 340 } 341 if (!egcd[0].isONE()) { 342 isunit = 0; 343 throw new NotInvertibleException("element not invertible (gcd)" + this); 344 } 345 isunit = 1; 346 C x = egcd[1]; 347 return new Residue<C>(ring, x); 348 } 349 if (val.isUnit()) { 350 C x = val.inverse(); 351 return new Residue<C>(ring, x); 352 } 353 //System.out.println("isunit = " + isunit + ", isUnit() = " + this.isUnit()); 354 throw new NotInvertibleException("element not invertible (!gcd)" + this); 355 } 356 357 358 /** 359 * Residue remainder. 360 * @param S Residue. 361 * @return this - (this/S)*S. 362 */ 363 public Residue<C> remainder(Residue<C> S) { 364 C x = val.remainder(S.val); 365 return new Residue<C>(ring, x); 366 } 367 368 369 /** 370 * Quotient and remainder by division of this by S. 371 * @param S a Residue 372 * @return [this/S, this - (this/S)*S]. 373 */ 374 @SuppressWarnings("unchecked") 375 public Residue<C>[] quotientRemainder(Residue<C> S) { 376 return new Residue[] { divide(S), remainder(S) }; 377 } 378 379 380 /** 381 * Residue multiplication. 382 * @param S Residue. 383 * @return this*S. 384 */ 385 public Residue<C> multiply(Residue<C> S) { 386 return new Residue<C>(ring, val.multiply(S.val)); 387 } 388 389 390 /** 391 * Greatest common divisor. <b>Note: </b>Not implemented, throws 392 * UnsupportedOperationException. 393 * @param b other element. 394 * @return gcd(this,b). 395 */ 396 public Residue<C> gcd(Residue<C> b) { 397 throw new UnsupportedOperationException("gcd not implemented " + this.getClass().getName()); 398 } 399 400 401 /** 402 * Extended greatest common divisor. <b>Note: </b>Not implemented, throws 403 * UnsupportedOperationException. 404 * @param b other element. 405 * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). 406 */ 407 public Residue<C>[] egcd(Residue<C> b) { 408 throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName()); 409 } 410 411}