001/* 002 * $Id$ 003 */ 004 005package edu.jas.application; 006 007 008import java.io.Reader; 009import java.util.ArrayList; 010import java.util.List; 011import java.util.Random; 012 013import org.apache.logging.log4j.Logger; 014import org.apache.logging.log4j.LogManager; 015 016import edu.jas.gb.SolvableGroebnerBaseAbstract; 017import edu.jas.gbufd.SGBFactory; 018import edu.jas.gbufd.SolvableSyzygyAbstract; 019import edu.jas.gbufd.SolvableSyzygySeq; 020import edu.jas.kern.StringUtil; 021import edu.jas.poly.GenPolynomial; 022import edu.jas.poly.GenSolvablePolynomial; 023import edu.jas.poly.GenSolvablePolynomialRing; 024import edu.jas.poly.PolynomialList; 025import edu.jas.structure.GcdRingElem; 026import edu.jas.structure.QuotPairFactory; 027import edu.jas.structure.RingFactory; 028 029 030/** 031 * SolvableLocalResidue ring factory for SolvableLocalResidue based on 032 * GenSolvablePolynomial with GcdRingElem interface. Objects of this class are 033 * immutable. It represents the "classical quotient ring modulo an ideal". 034 * @author Heinz Kredel 035 */ 036public class SolvableLocalResidueRing<C extends GcdRingElem<C>> implements 037 RingFactory<SolvableLocalResidue<C>>, 038 QuotPairFactory<GenPolynomial<C>, SolvableLocalResidue<C>> { 039 040 041 // Can not extend SolvableLocalRing or SolvableQuotientRing 042 // because of different constructor semantics. 043 044 045 private static final Logger logger = LogManager.getLogger(SolvableLocalResidueRing.class); 046 047 048 private static final boolean debug = logger.isDebugEnabled(); 049 050 051 /** 052 * Solvable polynomial ring of the factory. 053 */ 054 public final GenSolvablePolynomialRing<C> ring; 055 056 057 /** 058 * Solvable polynomial ideal for the reduction. 059 */ 060 public final SolvableIdeal<C> ideal; 061 062 063 /** 064 * Syzygy engine of the factory. 065 */ 066 public final SolvableSyzygyAbstract<C> engine; 067 068 069 /** 070 * Groebner base engine. 071 */ 072 protected final SolvableGroebnerBaseAbstract<C> bb; 073 074 075 /** 076 * Indicator if this ring is a field. 077 */ 078 protected int isField = -1; // initially unknown 079 080 081 /** 082 * The constructor creates a SolvableLocalResidueRing object from a 083 * SolvableIdeal. 084 * @param i ideal in solvable polynomial ring. 085 */ 086 public SolvableLocalResidueRing(SolvableIdeal<C> i) { 087 if (i == null) { 088 throw new IllegalArgumentException("ideal may not be null"); 089 } 090 ring = i.getRing(); 091 ideal = i.GB(); // cheap if isGB 092 if (ideal.isONE()) { 093 throw new IllegalArgumentException("ideal may not be 1"); 094 } 095 if (ideal.isMaximal()) { 096 isField = 1; 097 //} else if (ideal.isPrime()) { 098 // isField = 1; 099 } else { 100 //isField = 0; 101 logger.warn("ideal not maximal and not known to be prime"); 102 //throw new IllegalArgumentException("ideal must be prime or maximal"); 103 } 104 engine = new SolvableSyzygySeq<C>(ring.coFac); 105 bb = SGBFactory.getImplementation(ring.coFac); //new SolvableGroebnerBaseSeq<C>(); 106 logger.debug("solvable local residue ring constructed"); 107 } 108 109 110 /** 111 * Factory for base elements. 112 */ 113 public GenSolvablePolynomialRing<C> pairFactory() { 114 return ring; 115 } 116 117 118 /** 119 * Create from numerator. 120 */ 121 @SuppressWarnings("unchecked") 122 public SolvableLocalResidue<C> create(GenPolynomial<C> n) { 123 return new SolvableLocalResidue<C>(this, (GenSolvablePolynomial<C>) n); 124 } 125 126 127 /** 128 * Create from numerator, denominator pair. 129 */ 130 @SuppressWarnings("unchecked") 131 public SolvableLocalResidue<C> create(GenPolynomial<C> n, GenPolynomial<C> d) { 132 return new SolvableLocalResidue<C>(this, (GenSolvablePolynomial<C>) n, (GenSolvablePolynomial<C>) d); 133 } 134 135 136 /** 137 * Is this structure finite or infinite. 138 * @return true if this structure is finite, else false. 139 */ 140 public boolean isFinite() { 141 return ring.isFinite() && bb.commonZeroTest(ideal.getList()) <= 0; 142 } 143 144 145 /** 146 * Copy SolvableLocalResidue element c. 147 * @param c 148 * @return a copy of c. 149 */ 150 public SolvableLocalResidue<C> copy(SolvableLocalResidue<C> c) { 151 return new SolvableLocalResidue<C>(c.ring, c.num, c.den, true); 152 } 153 154 155 /** 156 * Get the zero element. 157 * @return 0 as SolvableLocalResidue. 158 */ 159 public SolvableLocalResidue<C> getZERO() { 160 return new SolvableLocalResidue<C>(this, ring.getZERO()); 161 } 162 163 164 /** 165 * Get the one element. 166 * @return 1 as SolvableLocalResidue. 167 */ 168 public SolvableLocalResidue<C> getONE() { 169 return new SolvableLocalResidue<C>(this, ring.getONE()); 170 } 171 172 173 /** 174 * Get a list of the generating elements. 175 * @return list of generators for the algebraic structure. 176 */ 177 public List<SolvableLocalResidue<C>> generators() { 178 List<GenSolvablePolynomial<C>> pgens = PolynomialList.<C> castToSolvableList(ring.generators()); 179 List<SolvableLocalResidue<C>> gens = new ArrayList<SolvableLocalResidue<C>>(pgens.size() * 2 - 1); 180 GenSolvablePolynomial<C> one = ring.getONE(); 181 for (GenSolvablePolynomial<C> p : pgens) { 182 SolvableLocalResidue<C> q = new SolvableLocalResidue<C>(this, p); 183 if (!q.isZERO() && !gens.contains(q)) { 184 gens.add(q); 185 if (!p.isONE() && !ideal.contains(p)) { 186 q = new SolvableLocalResidue<C>(this, one, p); 187 gens.add(q); 188 } 189 } 190 } 191 return gens; 192 } 193 194 195 /** 196 * Query if this ring is commutative. 197 * @return true if this ring is commutative, else false. 198 */ 199 public boolean isCommutative() { 200 return ring.isCommutative(); 201 } 202 203 204 /** 205 * Query if this ring is associative. 206 * @return true if this ring is associative, else false. 207 */ 208 @SuppressWarnings("unused") 209 public boolean isAssociative() { 210 if (!ring.isAssociative()) { 211 return false; 212 } 213 SolvableLocalResidue<C> Xi, Xj, Xk, p, q; 214 List<SolvableLocalResidue<C>> gens = generators(); 215 int ngen = gens.size(); 216 for (int i = 0; i < ngen; i++) { 217 Xi = gens.get(i); 218 for (int j = i + 1; j < ngen; j++) { 219 Xj = gens.get(j); 220 for (int k = j + 1; k < ngen; k++) { 221 Xk = gens.get(k); 222 if (Xi.num.degree() == 0 && Xj.num.degree() == 0 && Xk.num.degree() == 0 && 223 Xi.den.degree() == 0 && Xj.den.degree() == 0 && Xk.den.degree() == 0) { 224 //System.out.println("lr degree == 0"); 225 continue; // skip all base elements 226 } 227 try { 228 p = Xk.multiply(Xj).multiply(Xi); 229 q = Xk.multiply(Xj.multiply(Xi)); 230 } catch (IllegalArgumentException e) { 231 e.printStackTrace(); 232 continue; // ignore undefined multiplication 233 } 234 if (p.num.equals(q.num) && p.den.equals(q.den)) { // short cut 235 continue; 236 } 237 if (!p.equals(q)) { 238 //System.out.println("lr assoc: p = " + p.toScript()); 239 //System.out.println("lr assoc: q = " + q.toScript()); 240 //System.out.println("lr assoc: Xk = " + Xk.toScript() + ", Xj = " + Xj.toScript() + ", Xi = " + Xi.toScript()); 241 logger.info("Xk = {}, Xj = {}, Xi = {}", Xk, Xj, Xi); 242 logger.info("p = ( Xk * Xj ) * Xi = {}", p); 243 logger.info("q = Xk * ( Xj * Xi ) = {}", q); 244 return false; 245 } 246 } 247 } 248 } 249 return true; 250 } 251 252 253 /** 254 * Query if this ring is a field. 255 * @return true. 256 */ 257 public boolean isField() { 258 if (isField > 0) { 259 return true; 260 } 261 if (isField == 0) { 262 return false; 263 } 264 // not reached 265 return false; 266 } 267 268 269 /** 270 * Characteristic of this ring. 271 * @return characteristic of this ring. 272 */ 273 public java.math.BigInteger characteristic() { 274 return ring.characteristic(); 275 } 276 277 278 /** 279 * Get a SolvableLocalResidue element from a BigInteger value. 280 * @param a BigInteger. 281 * @return a SolvableLocalResidue. 282 */ 283 public SolvableLocalResidue<C> fromInteger(java.math.BigInteger a) { 284 return new SolvableLocalResidue<C>(this, ring.fromInteger(a)); 285 } 286 287 288 /** 289 * Get a SolvableLocalResidue element from a long value. 290 * @param a long. 291 * @return a SolvableLocalResidue. 292 */ 293 public SolvableLocalResidue<C> fromInteger(long a) { 294 return new SolvableLocalResidue<C>(this, ring.fromInteger(a)); 295 } 296 297 298 /** 299 * Get the String representation as RingFactory. 300 */ 301 @Override 302 public String toString() { 303 return "SolvableLocalResidueRing[ " + ideal.toString() + " ]"; 304 } 305 306 307 /** 308 * Get a scripting compatible string representation. 309 * @return script compatible representation for this ElemFactory. 310 */ 311 @Override 312 public String toScript() { 313 // Python case 314 return "SLR(" + ideal.list.toScript() + ")"; 315 } 316 317 318 /** 319 * Comparison with any other object. 320 */ 321 @Override 322 @SuppressWarnings("unchecked") 323 public boolean equals(Object b) { 324 if (!(b instanceof SolvableLocalResidueRing)) { 325 return false; 326 } 327 SolvableLocalResidueRing<C> a = null; 328 try { 329 a = (SolvableLocalResidueRing<C>) b; 330 } catch (ClassCastException e) { 331 } 332 if (a == null) { 333 return false; 334 } 335 return ring.equals(a.ring); 336 } 337 338 339 /** 340 * Hash code for this quotient ring. 341 */ 342 @Override 343 public int hashCode() { 344 int h; 345 h = ideal.hashCode(); 346 return h; 347 } 348 349 350 /** 351 * SolvableLocalResidue random. 352 * @param n such that 0 ≤ v ≤ (2<sup>n</sup>-1). 353 * @return a random quotient element. 354 */ 355 public SolvableLocalResidue<C> random(int n) { 356 GenSolvablePolynomial<C> r = ring.random(n).monic(); 357 r = ideal.normalform(r); 358 GenSolvablePolynomial<C> s; 359 do { 360 s = ring.random(n).monic(); 361 s = ideal.normalform(s); 362 } while (s.isZERO()); 363 return new SolvableLocalResidue<C>(this, r, s, false); 364 } 365 366 367 /** 368 * Generate a random quotient. 369 * @param k bitsize of random coefficients. 370 * @param l number of terms. 371 * @param d maximal degree in each variable. 372 * @param q density of nozero exponents. 373 * @return a random quotient. 374 */ 375 public SolvableLocalResidue<C> random(int k, int l, int d, float q) { 376 GenSolvablePolynomial<C> r = ring.random(k, l, d, q).monic(); 377 r = ideal.normalform(r); 378 GenSolvablePolynomial<C> s; 379 do { 380 s = ring.random(k, l, d, q).monic(); 381 s = ideal.normalform(s); 382 } while (s.isZERO()); 383 return new SolvableLocalResidue<C>(this, r, s, false); 384 } 385 386 387 /** 388 * SolvableLocalResidue random. 389 * @param n such that 0 ≤ v ≤ (2<sup>n</sup>-1). 390 * @param rnd is a source for random bits. 391 * @return a random quotient element. 392 */ 393 public SolvableLocalResidue<C> random(int n, Random rnd) { 394 GenSolvablePolynomial<C> r = ring.random(n, rnd).monic(); 395 r = ideal.normalform(r); 396 GenSolvablePolynomial<C> s; 397 do { 398 s = ring.random(n, rnd).monic(); 399 s = ideal.normalform(s); 400 } while (s.isZERO()); 401 return new SolvableLocalResidue<C>(this, r, s, false); 402 } 403 404 405 /** 406 * Parse SolvableLocalResidue from String. Syntax: 407 * "{ polynomial | polynomial }" or "{ polynomial }" or 408 * " polynomial | polynomial " or " polynomial " 409 * @param s String. 410 * @return SolvableLocalResidue from s. 411 */ 412 public SolvableLocalResidue<C> parse(String s) { 413 int i = s.indexOf("{"); 414 if (i >= 0) { 415 s = s.substring(i + 1); 416 } 417 i = s.lastIndexOf("}"); 418 if (i >= 0) { 419 s = s.substring(0, i); 420 } 421 i = s.indexOf("|"); 422 if (i < 0) { 423 GenSolvablePolynomial<C> n = ring.parse(s); 424 return new SolvableLocalResidue<C>(this, n); 425 } 426 String s1 = s.substring(0, i); 427 String s2 = s.substring(i + 1); 428 GenSolvablePolynomial<C> n = ring.parse(s1); 429 GenSolvablePolynomial<C> d = ring.parse(s2); 430 return new SolvableLocalResidue<C>(this, n, d); 431 } 432 433 434 /** 435 * Parse SolvableLocalResidue from Reader. 436 * @param r Reader. 437 * @return next SolvableLocalResidue from r. 438 */ 439 public SolvableLocalResidue<C> parse(Reader r) { 440 String s = StringUtil.nextPairedString(r, '{', '}'); 441 return parse(s); 442 } 443 444}