001/* 002 * $Id$ 003 */ 004 005package edu.jas.poly; 006 007 008import java.io.Reader; 009import java.util.ArrayList; 010import java.util.List; 011import java.util.Random; 012 013import org.apache.logging.log4j.LogManager; 014import org.apache.logging.log4j.Logger; 015 016import edu.jas.structure.RingElem; 017import edu.jas.structure.RingFactory; 018 019 020/** 021 * Residue ring factory based on RingElem and RingFactory module. Objects of 022 * this class are immutable. 023 * @author Heinz Kredel 024 */ 025public class ResidueRing<C extends RingElem<C>> implements RingFactory<Residue<C>> { 026 027 028 private static final Logger logger = LogManager.getLogger(ResidueRing.class); 029 030 031 //private static final boolean debug = logger.isDebugEnabled(); 032 033 034 /** 035 * Ring element for reduction. 036 */ 037 protected final C modul; 038 039 040 /** 041 * Ring factory. 042 */ 043 protected final RingFactory<C> ring; 044 045 046 /** 047 * Indicator if this ring is a field. 048 */ 049 protected int isField = -1; // initially unknown 050 051 052 /** 053 * The constructor creates a ResidueRing object from an ring factory and a 054 * modul. 055 * @param r ring factory. 056 * @param m modul. 057 */ 058 public ResidueRing(RingFactory<C> r, C m) { 059 ring = r; 060 if (m == null || m.isZERO()) { 061 throw new IllegalArgumentException("modul may not be null"); 062 } 063 if (m.isONE()) { 064 logger.warn("modul is one"); 065 } 066 if (m.signum() < 0) { 067 m = m.negate(); 068 } 069 modul = m; 070 } 071 072 073 /** 074 * Is this structure finite or infinite. 075 * @return true if this structure is finite, else false. 076 * @see edu.jas.structure.ElemFactory#isFinite() 077 */ 078 public boolean isFinite() { 079 //if (ring instanceof GenPolynomialRing pr) { // Java 17 080 if (ring instanceof GenPolynomialRing) { 081 GenPolynomialRing pr = (GenPolynomialRing) ring; 082 return pr.coFac.isFinite(); 083 /* always true: modul.degree() < \infinity */ 084 } 085 return true; // modul < Long.MAX_VALUE; 086 //throw new UnsupportedOperationException("not implemented"); 087 } 088 089 090 /** 091 * Copy Residue element c. 092 * @param c 093 * @return a copy of c. 094 */ 095 public Residue<C> copy(Residue<C> c) { 096 return new Residue<C>(c.ring, c.val); 097 } 098 099 100 /** 101 * Get the zero element. 102 * @return 0 as Residue. 103 */ 104 public Residue<C> getZERO() { 105 return new Residue<C>(this, ring.getZERO()); 106 } 107 108 109 /** 110 * Get the one element. 111 * @return 1 as Residue. 112 */ 113 public Residue<C> getONE() { 114 Residue<C> one = new Residue<C>(this, ring.getONE()); 115 if (one.isZERO()) { 116 logger.warn("one is zero, so all residues are 0"); 117 } 118 return one; 119 } 120 121 122 /** 123 * Get a list of the generating elements. 124 * @return list of generators for the algebraic structure. 125 * @see edu.jas.structure.ElemFactory#generators() 126 */ 127 public List<Residue<C>> generators() { 128 List<? extends C> rgens = ring.generators(); 129 List<Residue<C>> gens = new ArrayList<Residue<C>>(rgens.size()); 130 for (C c : rgens) { 131 gens.add(new Residue<C>(this, c)); 132 } 133 return gens; 134 } 135 136 137 /** 138 * Query if this ring is commutative. 139 * @return true if this ring is commutative, else false. 140 */ 141 public boolean isCommutative() { 142 return ring.isCommutative(); 143 } 144 145 146 /** 147 * Query if this ring is associative. 148 * @return true if this ring is associative, else false. 149 */ 150 public boolean isAssociative() { 151 return ring.isAssociative(); 152 } 153 154 155 /** 156 * Query if this ring is a field. 157 * @return false. 158 */ 159 public boolean isField() { 160 if (isField > 0) { 161 return true; 162 } 163 if (isField == 0) { 164 return false; 165 } 166 // ideal is prime ? 167 return false; 168 } 169 170 171 /** 172 * Characteristic of this ring. 173 * @return characteristic of this ring. 174 */ 175 public java.math.BigInteger characteristic() { 176 //if (ring instanceof GenPolynomialRing pr) { // Java 17 177 if (ring instanceof GenPolynomialRing) { 178 GenPolynomialRing pr = (GenPolynomialRing) ring; 179 return pr.characteristic(); 180 /* always true: modul.degree() < \infinity */ 181 } 182 // modul < Long.MAX_VALUE; 183 java.math.BigInteger m = new java.math.BigInteger(modul.toString()); 184 return m; 185 } 186 187 188 /** 189 * Get a Residue element from a BigInteger value. 190 * @param a BigInteger. 191 * @return a Residue. 192 */ 193 public Residue<C> fromInteger(java.math.BigInteger a) { 194 return new Residue<C>(this, ring.fromInteger(a)); 195 } 196 197 198 /** 199 * Get a Residue element from a long value. 200 * @param a long. 201 * @return a Residue. 202 */ 203 public Residue<C> fromInteger(long a) { 204 return new Residue<C>(this, ring.fromInteger(a)); 205 } 206 207 208 /** 209 * Get the String representation as RingFactory. 210 * @see java.lang.Object#toString() 211 */ 212 @Override 213 public String toString() { 214 return "Residue[ " + modul.toString() + " ]"; 215 } 216 217 218 /** 219 * Get a scripting compatible string representation. 220 * @return script compatible representation for this ElemFactory. 221 * @see edu.jas.structure.ElemFactory#toScript() 222 */ 223 @Override 224 public String toScript() { 225 // Python case 226 return "ResidueRing(" + modul.toScript() + ")"; 227 } 228 229 230 /** 231 * Comparison with any other object. 232 * @see java.lang.Object#equals(java.lang.Object) 233 */ 234 @Override 235 @SuppressWarnings("unchecked") 236 public boolean equals(Object b) { 237 if (b == null) { 238 return false; 239 } 240 if (!(b instanceof ResidueRing)) { 241 return false; 242 } 243 ResidueRing<C> a = (ResidueRing<C>) b; 244 if (!ring.equals(a.ring)) { 245 return false; 246 } 247 return modul.equals(a.modul); 248 } 249 250 251 /** 252 * Hash code for this residue ring. 253 * @see java.lang.Object#hashCode() 254 */ 255 @Override 256 public int hashCode() { 257 int h; 258 h = ring.hashCode(); 259 h = 37 * h + modul.hashCode(); 260 return h; 261 } 262 263 264 /** 265 * Residue random. 266 * @param n such that 0 ≤ v ≤ (2<sup>n</sup>-1). 267 * @return a random residue element. 268 */ 269 public Residue<C> random(int n) { 270 C x = ring.random(n); 271 // x = x.sum( ring.getONE() ); 272 return new Residue<C>(this, x); 273 } 274 275 276 /** 277 * Residue random. 278 * @param n such that 0 ≤ v ≤ (2<sup>n</sup>-1). 279 * @param rnd is a source for random bits. 280 * @return a random residue element. 281 */ 282 public Residue<C> random(int n, Random rnd) { 283 C x = ring.random(n, rnd); 284 // x = x.sum( ring.getONE() ); 285 return new Residue<C>(this, x); 286 } 287 288 289 /** 290 * Parse Residue from String. 291 * @param s String. 292 * @return Residue from s. 293 */ 294 public Residue<C> parse(String s) { 295 int i = s.indexOf("{"); 296 if (i >= 0) { 297 s = s.substring(i + 1); 298 } 299 i = s.lastIndexOf("}"); 300 if (i >= 0) { 301 s = s.substring(0, i); 302 } 303 C x = ring.parse(s); 304 return new Residue<C>(this, x); 305 } 306 307 308 /** 309 * Parse Residue from Reader. 310 * @param r Reader. 311 * @return next Residue from r. 312 */ 313 public Residue<C> parse(Reader r) { 314 C x = ring.parse(r); 315 return new Residue<C>(this, x); 316 } 317 318}