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