001/* 002 * $Id: GroebnerBaseFGLM.java 5687 2017-01-03 08:44:03Z kredel $ 003 */ 004 005package edu.jas.gbufd; 006 007 008import java.util.ArrayList; 009import java.util.List; 010 011import org.apache.log4j.Logger; 012 013import edu.jas.gb.GroebnerBaseAbstract; 014import edu.jas.gb.PairList; 015import edu.jas.gb.Reduction; 016import edu.jas.gb.ReductionSeq; 017import edu.jas.poly.ExpVector; 018import edu.jas.poly.GenPolynomial; 019import edu.jas.poly.GenPolynomialRing; 020import edu.jas.poly.PolyUtil; 021import edu.jas.poly.TermOrder; 022import edu.jas.structure.GcdRingElem; 023import edu.jas.structure.RingFactory; 024 025 026/** 027 * Groebner Base sequential FGLM algorithm. Implements Groebner base computation 028 * via FGLM algorithm. 029 * @param <C> coefficient type 030 * @author Jan Suess 031 * 032 * @see edu.jas.application.GBAlgorithmBuilder 033 * @see edu.jas.gbufd.GBFactory 034 */ 035public class GroebnerBaseFGLM<C extends GcdRingElem<C>> extends GroebnerBaseAbstract<C> { 036 037 038 private static final Logger logger = Logger.getLogger(GroebnerBaseFGLM.class); 039 040 041 //private static final boolean debug = logger.isDebugEnabled(); 042 043 044 /** 045 * The backing GB algorithm implementation. 046 */ 047 private GroebnerBaseAbstract<C> sgb; 048 049 050 /** 051 * Constructor. 052 */ 053 public GroebnerBaseFGLM() { 054 super(); 055 sgb = null; 056 } 057 058 059 /** 060 * Constructor. 061 * @param red Reduction engine 062 */ 063 public GroebnerBaseFGLM(Reduction<C> red) { 064 super(red); 065 sgb = null; 066 } 067 068 069 /** 070 * Constructor. 071 * @param red Reduction engine 072 * @param pl pair selection strategy 073 */ 074 public GroebnerBaseFGLM(Reduction<C> red, PairList<C> pl) { 075 super(red, pl); 076 sgb = null; 077 } 078 079 080 /** 081 * Constructor. 082 * @param red Reduction engine 083 * @param pl pair selection strategy 084 * @param gb backing GB algorithm. 085 */ 086 public GroebnerBaseFGLM(Reduction<C> red, PairList<C> pl, GroebnerBaseAbstract<C> gb) { 087 super(red, pl); 088 sgb = gb; 089 } 090 091 092 /** 093 * Constructor. 094 * @param gb backing GB algorithm. 095 */ 096 public GroebnerBaseFGLM(GroebnerBaseAbstract<C> gb) { 097 super(); 098 sgb = gb; 099 } 100 101 102 /** 103 * Get the String representation with GB engine. 104 * @see java.lang.Object#toString() 105 */ 106 @Override 107 public String toString() { 108 if (sgb == null) { 109 return "GroebnerBaseFGLM()"; 110 } 111 return "GroebnerBaseFGLM( " + sgb.toString() + " )"; 112 } 113 114 115 /** 116 * Groebner base using FGLM algorithm. 117 * @param modv module variable number. 118 * @param F polynomial list. 119 * @return GB(F) a inv lex term order Groebner base of F. 120 */ 121 public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) { 122 if (modv != 0) { 123 throw new UnsupportedOperationException("case modv != 0 not yet implemented"); 124 } 125 if (F == null || F.size() == 0) { 126 return F; 127 } 128 List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>(); 129 if (F.size() <= 1) { 130 GenPolynomial<C> p = F.get(0).monic(); 131 G.add(p); 132 return G; 133 } 134 // convert to graded term order 135 List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F.size()); 136 GenPolynomialRing<C> pfac = F.get(0).ring; 137 if (!pfac.coFac.isField()) { 138 throw new IllegalArgumentException("coefficients not from a field: " + pfac.coFac); 139 } 140 TermOrder tord = new TermOrder(TermOrder.IGRLEX); 141 GenPolynomialRing<C> gfac = new GenPolynomialRing<C>(pfac.coFac, pfac.nvar, tord, pfac.getVars()); 142 for (GenPolynomial<C> p : F) { 143 GenPolynomial<C> g = gfac.copy(p); // change term order 144 Fp.add(g); 145 } 146 // compute graded term order Groebner base 147 if (sgb == null) { 148 sgb = GBFactory.<C> getImplementation(pfac.coFac, strategy); 149 } 150 List<GenPolynomial<C>> Gp = sgb.GB(modv, Fp); 151 logger.info("graded GB = " + Gp); 152 if (tord.equals(pfac.tord)) { 153 return Gp; 154 } 155 if (Gp.size() == 0) { 156 return Gp; 157 } 158 if (Gp.size() == 1) { // also dimension -1 159 GenPolynomial<C> p = pfac.copy(Gp.get(0)); // change term order 160 G.add(p); 161 return G; 162 } 163 // check dimension zero 164 int z = commonZeroTest(Gp); 165 if (z > 0) { 166 logger.error("use Groebner Walk algorithm"); 167 throw new IllegalArgumentException("ideal(G) not zero dimensional, dim = " + z); 168 } 169 // compute invlex Groebner base via FGLM 170 G = convGroebnerToLex(Gp); 171 return G; 172 } 173 174 175 /** 176 * Algorithm CONVGROEBNER: Converts Groebner bases w.r.t. total degree 177 * termorder into Groebner base w.r.t to inverse lexicographical term order 178 * @return Groebner base w.r.t to inverse lexicographical term order 179 */ 180 public List<GenPolynomial<C>> convGroebnerToLex(List<GenPolynomial<C>> groebnerBasis) { 181 if (groebnerBasis == null || groebnerBasis.size() == 0) { 182 throw new IllegalArgumentException("G may not be null or empty"); 183 } 184 //Polynomial ring of input Groebnerbasis G 185 GenPolynomialRing<C> ring = groebnerBasis.get(0).ring; 186 int numberOfVariables = ring.nvar; //Number of Variables of the given Polynomial Ring 187 String[] ArrayOfVariables = ring.getVars(); //Variables of given polynomial ring w.r.t. to input G 188 RingFactory<C> cfac = ring.coFac; 189 190 //Main Algorithm 191 //Initialization 192 193 TermOrder invlex = new TermOrder(TermOrder.INVLEX); 194 //Polynomial ring of newGB with invlex order 195 GenPolynomialRing<C> ufac = new GenPolynomialRing<C>(cfac, numberOfVariables, invlex, 196 ArrayOfVariables); 197 198 //Local Lists 199 List<GenPolynomial<C>> newGB = new ArrayList<GenPolynomial<C>>(); //Instantiate the return list of polynomials 200 List<GenPolynomial<C>> H = new ArrayList<GenPolynomial<C>>(); //Instantiate a help list of polynomials 201 List<GenPolynomial<C>> redTerms = new ArrayList<GenPolynomial<C>>();//Instantiate the return list of reduced terms 202 203 //Local Polynomials 204 GenPolynomial<C> t = ring.ONE; //Create ONE polynom of original polynomial ring 205 GenPolynomial<C> h; //Create help polynomial 206 GenPolynomial<GenPolynomial<C>> hh; //h as polynomial in rfac 207 GenPolynomial<GenPolynomial<C>> p; //Create another help polynomial 208 redTerms.add(t); //Add ONE to list of reduced terms 209 210 //create new indeterminate Y1 211 int indeterminates = 1; //Number of indeterminates, starting with Y1 212 GenPolynomialRing<C> cpfac = createRingOfIndeterminates(ring, indeterminates); 213 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cpfac, ring); 214 GenPolynomial<GenPolynomial<C>> q = rfac.getZERO().sum(cpfac.univariate(0)); 215 216 //Main while loop 217 int z = -1; 218 t = lMinterm(H, t); 219 while (t != null) { 220 //System.out.println("t = " + t); 221 h = red.normalform(groebnerBasis, t); 222 //System.out.println("Zwischennormalform h = " + h.toString()); 223 hh = PolyUtil.<C> toRecursive(rfac, h); 224 p = hh.sum(q); 225 List<GenPolynomial<C>> Cf = new ArrayList<GenPolynomial<C>>(p.getMap().values()); 226 Cf = red.irreducibleSet(Cf); 227 //System.out.println("Cf = " + Cf); 228 //System.out.println("Current Polynomial ring in Y_n: " + rfac.toString()); 229 230 z = commonZeroTest(Cf); 231 //System.out.println("z = " + z); 232 if (z != 0) { //z=1 OR z=-1 --> Infinite number of solutions OR No solution 233 indeterminates++; //then, increase number of indeterminates by one 234 redTerms.add(t); //add current t to list of reduced terms 235 cpfac = addIndeterminate(cpfac); 236 rfac = new GenPolynomialRing<GenPolynomial<C>>(cpfac, ring); 237 hh = PolyUtil.<C> toRecursive(rfac, h); 238 GenPolynomial<GenPolynomial<C>> Yt = rfac.getZERO().sum(cpfac.univariate(0)); 239 GenPolynomial<GenPolynomial<C>> Yth = hh.multiply(Yt); 240 q = PolyUtil.<C> extendCoefficients(rfac, q, 0, 0L); 241 q = Yth.sum(q); 242 } else { // z=0 --> one solution 243 GenPolynomial<C> g = ufac.getZERO(); 244 for (GenPolynomial<C> pc : Cf) { 245 ExpVector e = pc.leadingExpVector(); 246 //System.out.println("e = " + e); 247 if (e == null) { 248 continue; 249 } 250 int[] v = e.dependencyOnVariables(); 251 if (v == null || v.length == 0) { 252 continue; 253 } 254 int vi = v[0]; 255 vi = indeterminates - vi; 256 C tc = pc.trailingBaseCoefficient(); 257 if (!tc.isZERO()) { 258 tc = tc.negate(); 259 GenPolynomial<C> csRedterm = redTerms.get(vi - 1).multiply(tc); 260 //System.out.println("csRedterm = " + csRedterm); 261 g = g.sum(csRedterm); 262 } 263 } 264 g = g.sum(t); 265 g = ufac.copy(g); 266 H.add(t); 267 if (!g.isZERO()) { 268 newGB.add(g); 269 logger.info("new element for GB = " + g.leadingExpVector()); 270 } 271 } 272 t = lMinterm(H, t); // compute lMINTERM of current t (lexMinterm) 273 } 274 //logger.info("GB = " + newGB); 275 return newGB; 276 } 277 278 279 /** 280 * Algorithm lMinterm: MINTERM algorithm for inverse lexicographical term 281 * order. 282 * @param t Term 283 * @param G Groebner basis 284 * @return Term that specifies condition (D) or null (Condition (D) in 285 * "A computational approach to commutative algebra", Becker, 286 * Weispfenning, Kredel 1993, p. 427) 287 */ 288 public GenPolynomial<C> lMinterm(List<GenPolynomial<C>> G, GenPolynomial<C> t) { 289 //not ok: if ( G == null || G.size() == 0 ) ... 290 GenPolynomialRing<C> ring = t.ring; 291 int numberOfVariables = ring.nvar; 292 GenPolynomial<C> u = new GenPolynomial<C>(ring, t.leadingBaseCoefficient(), t.leadingExpVector()); //HeadTerm of of input polynomial 293 ReductionSeq<C> redHelp = new ReductionSeq<C>(); // Create instance of ReductionSeq to use method isReducible 294 //not ok: if ( redHelp.isTopReducible(G,u) ) ... 295 for (int i = numberOfVariables - 1; i >= 0; i--) { // Walk through all variables, starting with least w.r.t to lex-order 296 GenPolynomial<C> x = ring.univariate(i); // Create Linear Polynomial X_i 297 u = u.multiply(x); // Multiply current u with x 298 if (!redHelp.isTopReducible(G, u)) { // Check if any term in HT(G) divides current u 299 return u; 300 } 301 GenPolynomial<C> s = ring.univariate(i, u.degree(numberOfVariables - (i + 1))); //if not, eliminate variable x_i 302 u = u.divide(s); 303 } 304 return null; 305 } 306 307 308 /** 309 * Compute the residues to given polynomial list. 310 * @return List of reduced terms 311 */ 312 public List<GenPolynomial<C>> redTerms(List<GenPolynomial<C>> groebnerBasis) { 313 if (groebnerBasis == null || groebnerBasis.size() == 0) { 314 throw new IllegalArgumentException("groebnerBasis may not be null or empty"); 315 } 316 GenPolynomialRing<C> ring = groebnerBasis.get(0).ring; 317 int numberOfVariables = ring.nvar; //Number of Variables of the given Polynomial Ring 318 long[] degrees = new long[numberOfVariables]; //Array for the degree-limits for the reduced terms 319 320 List<GenPolynomial<C>> terms = new ArrayList<GenPolynomial<C>>(); //Instantiate the return object 321 for (GenPolynomial<C> g : groebnerBasis) { //For each polynomial of G 322 if (g.isONE()) { 323 terms.clear(); 324 return terms; //If 1 e G, return empty list terms 325 } 326 ExpVector e = g.leadingExpVector(); //Take the exponent of the leading monomial 327 if (e.totalDeg() == e.maxDeg()) { //and check, whether a variable x_i is isolated 328 for (int i = 0; i < numberOfVariables; i++) { 329 long exp = e.getVal(i); 330 if (exp > 0) { 331 degrees[i] = exp; //if true, add the degree of univariate x_i to array degrees 332 } 333 } 334 } 335 } 336 long max = maxArray(degrees); //Find maximum in Array degrees 337 for (int i = 0; i < degrees.length; i++) { //Set all zero grades to maximum of array "degrees" 338 if (degrees[i] == 0) { 339 logger.info("dimension not zero, setting degree to " + max); 340 degrees[i] = max; //--> to "make" the ideal zero-dimensional 341 } 342 } 343 terms.add(ring.ONE); //Add the one-polynomial of the ring to the list of reduced terms 344 ReductionSeq<C> s = new ReductionSeq<C>(); //Create instance of ReductionSeq to use method isReducible 345 346 //Main Algorithm 347 for (int i = 0; i < numberOfVariables; i++) { 348 GenPolynomial<C> x = ring.univariate(i); //Create Linear Polynomial X_i 349 List<GenPolynomial<C>> S = new ArrayList<GenPolynomial<C>>(terms); //Copy all entries of return list "terms" into list "S" 350 for (GenPolynomial<C> t : S) { 351 for (int l = 1; l <= degrees[i]; l++) { 352 t = t.multiply(x); //Multiply current element t with Linear Polynomial X_i 353 if (!s.isReducible(groebnerBasis, t)) { //Check, if t is irreducible mod groebnerbase 354 terms.add(t); //Add t to return list terms 355 } 356 } 357 } 358 } 359 return terms; 360 } 361 362 363 /** 364 * Internal method to create a polynomial ring in i indeterminates. Create 365 * new ring over coefficients of ring with i variables Y1,...,Yi 366 * (indeterminate) 367 * @return polynomial ring with variables Y1...Yi and coefficient of ring. 368 */ 369 GenPolynomialRing<C> createRingOfIndeterminates(GenPolynomialRing<C> ring, int i) { 370 RingFactory<C> cfac = ring.coFac; 371 int indeterminates = i; 372 String[] stringIndeterminates = new String[indeterminates]; 373 for (int j = 1; j <= indeterminates; j++) { 374 stringIndeterminates[j - 1] = ("Y" + j); 375 } 376 TermOrder invlex = new TermOrder(TermOrder.INVLEX); 377 GenPolynomialRing<C> cpfac = new GenPolynomialRing<C>(cfac, indeterminates, invlex, 378 stringIndeterminates); 379 return cpfac; 380 } 381 382 383 /** 384 * Internal method to add new indeterminates. Add another variabe 385 * (indeterminate) Y_{i+1} to existing ring 386 * @return polynomial ring with variables Y1,..,Yi,Yi+1 and coefficients of 387 * ring. 388 */ 389 GenPolynomialRing<C> addIndeterminate(GenPolynomialRing<C> ring) { 390 String[] stringIndeterminates = new String[1]; 391 int number = ring.nvar + 1; 392 stringIndeterminates[0] = ("Y" + number); 393 ring = ring.extend(stringIndeterminates); 394 return ring; 395 } 396 397 398 /** 399 * Maximum of an array. 400 * @return maximum of an array 401 */ 402 long maxArray(long[] t) { 403 if (t.length == 0) { 404 return 0L; 405 } 406 long maximum = t[0]; 407 for (int i = 1; i < t.length; i++) { 408 if (t[i] > maximum) { 409 maximum = t[i]; 410 } 411 } 412 return maximum; 413 } 414 415 416 /** 417 * Cleanup and terminate ThreadPool. 418 */ 419 @Override 420 public void terminate() { 421 if (sgb == null) { 422 return; 423 } 424 sgb.terminate(); 425 } 426 427 428 /** 429 * Cancel ThreadPool. 430 */ 431 @Override 432 public int cancel() { 433 if (sgb == null) { 434 return 0; 435 } 436 return sgb.cancel(); 437 } 438 439}