001/* 002 * $Id: SolvableLocalResidueRing.java 5868 2018-07-20 15:44:13Z kredel $ 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 // } else { 237 // int s = p.num.length() + q.num.length() + p.den.length() + q.den.length(); 238 // if (s > 5) { 239 // System.out.println("lr assoc: p = " + p.toScript()); 240 // System.out.println("lr assoc: q = " + q.toScript()); 241 // System.out.println("lr assoc: Xk = " + Xk.toScript() + ", Xj = " + Xj.toScript() + ", Xi = " + Xi.toScript()); 242 // System.out.println("lr size = " + s); 243 // continue; 244 // } 245 } 246 if (!p.equals(q)) { 247 if (true || debug) { 248 System.out.println("lr assoc: p = " + p.toScript()); 249 System.out.println("lr assoc: q = " + q.toScript()); 250 System.out.println("lr assoc: Xk = " + Xk.toScript() + ", Xj = " + Xj.toScript() + ", Xi = " + Xi.toScript()); 251 logger.info("Xk = " + Xk + ", Xj = " + Xj + ", Xi = " + Xi); 252 logger.info("p = ( Xk * Xj ) * Xi = " + p); 253 logger.info("q = Xk * ( Xj * Xi ) = " + q); 254 } 255 return false; 256 } 257 } 258 } 259 } 260 return true; 261 } 262 263 264 /** 265 * Query if this ring is a field. 266 * @return true. 267 */ 268 public boolean isField() { 269 if (isField > 0) { 270 return true; 271 } 272 if (isField == 0) { 273 return false; 274 } 275 // not reached 276 return false; 277 } 278 279 280 /** 281 * Characteristic of this ring. 282 * @return characteristic of this ring. 283 */ 284 public java.math.BigInteger characteristic() { 285 return ring.characteristic(); 286 } 287 288 289 /** 290 * Get a SolvableLocalResidue element from a BigInteger value. 291 * @param a BigInteger. 292 * @return a SolvableLocalResidue. 293 */ 294 public SolvableLocalResidue<C> fromInteger(java.math.BigInteger a) { 295 return new SolvableLocalResidue<C>(this, ring.fromInteger(a)); 296 } 297 298 299 /** 300 * Get a SolvableLocalResidue element from a long value. 301 * @param a long. 302 * @return a SolvableLocalResidue. 303 */ 304 public SolvableLocalResidue<C> fromInteger(long a) { 305 return new SolvableLocalResidue<C>(this, ring.fromInteger(a)); 306 } 307 308 309 /** 310 * Get the String representation as RingFactory. 311 */ 312 @Override 313 public String toString() { 314 return "SolvableLocalResidueRing[ " + ideal.toString() + " ]"; 315 } 316 317 318 /** 319 * Get a scripting compatible string representation. 320 * @return script compatible representation for this ElemFactory. 321 */ 322 @Override 323 public String toScript() { 324 // Python case 325 return "SLR(" + ideal.list.toScript() + ")"; 326 } 327 328 329 /** 330 * Comparison with any other object. 331 */ 332 @Override 333 @SuppressWarnings("unchecked") 334 public boolean equals(Object b) { 335 if (!(b instanceof SolvableLocalResidueRing)) { 336 return false; 337 } 338 SolvableLocalResidueRing<C> a = null; 339 try { 340 a = (SolvableLocalResidueRing<C>) b; 341 } catch (ClassCastException e) { 342 } 343 if (a == null) { 344 return false; 345 } 346 return ring.equals(a.ring); 347 } 348 349 350 /** 351 * Hash code for this quotient ring. 352 */ 353 @Override 354 public int hashCode() { 355 int h; 356 h = ideal.hashCode(); 357 return h; 358 } 359 360 361 /** 362 * SolvableLocalResidue random. 363 * @param n such that 0 ≤ v ≤ (2<sup>n</sup>-1). 364 * @return a random quotient element. 365 */ 366 public SolvableLocalResidue<C> random(int n) { 367 GenSolvablePolynomial<C> r = ring.random(n).monic(); 368 r = ideal.normalform(r); 369 GenSolvablePolynomial<C> s; 370 do { 371 s = ring.random(n).monic(); 372 s = ideal.normalform(s); 373 } while (s.isZERO()); 374 return new SolvableLocalResidue<C>(this, r, s, false); 375 } 376 377 378 /** 379 * Generate a random quotient. 380 * @param k bitsize of random coefficients. 381 * @param l number of terms. 382 * @param d maximal degree in each variable. 383 * @param q density of nozero exponents. 384 * @return a random quotient. 385 */ 386 public SolvableLocalResidue<C> random(int k, int l, int d, float q) { 387 GenSolvablePolynomial<C> r = ring.random(k, l, d, q).monic(); 388 r = ideal.normalform(r); 389 GenSolvablePolynomial<C> s; 390 do { 391 s = ring.random(k, l, d, q).monic(); 392 s = ideal.normalform(s); 393 } while (s.isZERO()); 394 return new SolvableLocalResidue<C>(this, r, s, false); 395 } 396 397 398 /** 399 * SolvableLocalResidue random. 400 * @param n such that 0 ≤ v ≤ (2<sup>n</sup>-1). 401 * @param rnd is a source for random bits. 402 * @return a random quotient element. 403 */ 404 public SolvableLocalResidue<C> random(int n, Random rnd) { 405 GenSolvablePolynomial<C> r = ring.random(n, rnd).monic(); 406 r = ideal.normalform(r); 407 GenSolvablePolynomial<C> s; 408 do { 409 s = ring.random(n, rnd).monic(); 410 s = ideal.normalform(s); 411 } while (s.isZERO()); 412 return new SolvableLocalResidue<C>(this, r, s, false); 413 } 414 415 416 /** 417 * Parse SolvableLocalResidue from String. Syntax: 418 * "{ polynomial | polynomial }" or "{ polynomial }" or 419 * " polynomial | polynomial " or " polynomial " 420 * @param s String. 421 * @return SolvableLocalResidue from s. 422 */ 423 public SolvableLocalResidue<C> parse(String s) { 424 int i = s.indexOf("{"); 425 if (i >= 0) { 426 s = s.substring(i + 1); 427 } 428 i = s.lastIndexOf("}"); 429 if (i >= 0) { 430 s = s.substring(0, i); 431 } 432 i = s.indexOf("|"); 433 if (i < 0) { 434 GenSolvablePolynomial<C> n = ring.parse(s); 435 return new SolvableLocalResidue<C>(this, n); 436 } 437 String s1 = s.substring(0, i); 438 String s2 = s.substring(i + 1); 439 GenSolvablePolynomial<C> n = ring.parse(s1); 440 GenSolvablePolynomial<C> d = ring.parse(s2); 441 return new SolvableLocalResidue<C>(this, n, d); 442 } 443 444 445 /** 446 * Parse SolvableLocalResidue from Reader. 447 * @param r Reader. 448 * @return next SolvableLocalResidue from r. 449 */ 450 public SolvableLocalResidue<C> parse(Reader r) { 451 String s = StringUtil.nextPairedString(r, '{', '}'); 452 return parse(s); 453 } 454 455}