001/* 002 * $Id: GroebnerBaseWalk.java 5731 2017-02-11 11:38:15Z kredel $ 003 */ 004 005package edu.jas.gbufd; 006 007 008import java.util.ArrayList; 009import java.util.List; 010import java.util.Set; 011import java.util.SortedSet; 012 013import org.apache.log4j.Logger; 014 015import edu.jas.gb.GroebnerBaseAbstract; 016import edu.jas.gb.ReductionAbstract; 017import edu.jas.poly.ExpVector; 018import edu.jas.poly.GenPolynomial; 019import edu.jas.poly.GenPolynomialRing; 020import edu.jas.poly.Monomial; 021import edu.jas.poly.PolyUtil; 022import edu.jas.poly.PolynomialList; 023import edu.jas.poly.TermOrder; 024import edu.jas.poly.TermOrderByName; 025import edu.jas.structure.GcdRingElem; 026import edu.jas.structure.RingFactory; 027 028 029/** 030 * Groebner Base sequential Groebner Walk algorithm. Implements Groebner base 031 * computation via Groebner Walk algorithm. See "The generic Groebner walk" by 032 * Fukuda, Jensen, Lauritzen, Thomas, 2005. 033 * 034 * The start term order t1 can be set by a constructor. The target term order t2 035 * is taken from the input polynomials term order. 036 * 037 * @param <C> coefficient type 038 * @author Heinz Kredel 039 * 040 * @see edu.jas.application.GBAlgorithmBuilder 041 * @see edu.jas.gbufd.GBFactory 042 */ 043public class GroebnerBaseWalk<C extends GcdRingElem<C>> extends GroebnerBaseAbstract<C> { 044 045 046 private static final Logger logger = Logger.getLogger(GroebnerBaseWalk.class); 047 048 049 private static final boolean debug = logger.isDebugEnabled(); 050 051 052 /** 053 * The backing GB algorithm implementation. 054 */ 055 protected GroebnerBaseAbstract<C> sgb; 056 057 058 /** 059 * The start term order t1. 060 */ 061 //protected TermOrder startTO = TermOrderByName.IGRLEX.blockOrder(2); 062 protected TermOrder startTO = TermOrderByName.IGRLEX; 063 064 065 /** 066 * Print intermediate GB after this number of iterations. 067 */ 068 int iterPrint = 100; 069 070 071 /** 072 * Constructor. 073 */ 074 public GroebnerBaseWalk() { 075 super(); 076 sgb = null; 077 } 078 079 080 /** 081 * Constructor. 082 * @param coFac coefficient ring of polynomial ring. 083 */ 084 public GroebnerBaseWalk(RingFactory<C> coFac) { 085 this(GBFactory.<C> getImplementation(coFac)); 086 } 087 088 089 /** 090 * Constructor. 091 * @param coFac coefficient ring of polynomial ring. 092 * @param t1 start term order. 093 */ 094 public GroebnerBaseWalk(RingFactory<C> coFac, TermOrder t1) { 095 this(GBFactory.<C> getImplementation(coFac), t1); 096 } 097 098 099 /** 100 * Constructor. 101 * @param gb backing GB algorithm. 102 */ 103 public GroebnerBaseWalk(GroebnerBaseAbstract<C> gb) { 104 super(gb.red, gb.strategy); 105 sgb = gb; 106 } 107 108 109 /** 110 * Constructor. 111 * @param gb backing GB algorithm. 112 * @param t1 start term order. 113 */ 114 public GroebnerBaseWalk(GroebnerBaseAbstract<C> gb, TermOrder t1) { 115 this(gb); 116 startTO = t1; 117 } 118 119 120 /** 121 * Get the String representation with GB engine. 122 * @see java.lang.Object#toString() 123 */ 124 @Override 125 public String toString() { 126 if (sgb == null) { 127 return "GroebnerBaseWalk(" + startTO.toScript() + ")"; 128 } 129 return "GroebnerBaseWalk( " + sgb.toString() + ", " + startTO.toScript() + " )"; 130 } 131 132 133 /** 134 * Groebner base using Groebner Walk algorithm. 135 * @param modv module variable number. 136 * @param F polynomial list in target term order. 137 * @return GB(F) a INVLEX / target term order Groebner base of F. 138 */ 139 public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) { 140 List<GenPolynomial<C>> G = normalizeZerosOnes(F); 141 G = PolyUtil.<C> monic(G); 142 if (G == null || G.size() == 0) { 143 return G; 144 } 145 GenPolynomialRing<C> pfac = G.get(0).ring; 146 if (!pfac.coFac.isField()) { 147 throw new IllegalArgumentException("coefficients not from a field: " + pfac.coFac); 148 } 149 if (G.size() <= 1) { 150 GenPolynomial<C> p = pfac.copy(G.get(0)); // change term order 151 G.clear(); 152 G.add(p); 153 return G; 154 } 155 // compute in graded / start term order 156 TermOrder grord = startTO; //new TermOrder(TermOrder.IGRLEX); 157 GenPolynomialRing<C> gfac = new GenPolynomialRing<C>(pfac, grord); 158 if (debug) { 159 logger.info("gfac = " + gfac.toScript()); 160 } 161 List<GenPolynomial<C>> Fp = gfac.copy(F); 162 logger.info("Term order: graded = " + grord + ", target = " + pfac.tord); 163 164 // compute graded / start term order Groebner base 165 if (sgb == null) { 166 sgb = GBFactory.<C> getImplementation(pfac.coFac, strategy); 167 } 168 List<GenPolynomial<C>> Gp = sgb.GB(modv, Fp); 169 logger.info("graded / start GB = " + Gp); 170 if (grord.equals(pfac.tord)) { 171 return Gp; 172 } 173 if (Gp.size() == 1) { // also dimension -1 174 GenPolynomial<C> p = pfac.copy(Gp.get(0)); // change term order 175 G.clear(); 176 G.add(p); 177 return G; 178 } 179 // info on FGLM 180 int z = commonZeroTest(Gp); 181 if (z == 0) { 182 logger.info("ideal zero dimensional, can use also FGLM algorithm"); 183 } 184 // compute target term order Groebner base via Groebner Walk 185 G = walkGroebnerToTarget(modv, Gp, pfac); 186 return G; 187 } 188 189 190 /** 191 * Converts Groebner bases w.r.t. total degree / start term order to 192 * Groebner base w.r.t to inverse lexicographical / target term order. 193 * @param modv module variable number. 194 * @param Gl Groebner base with respect to graded / start term order. 195 * @param ufac target polynomial ring and term order. 196 * @return Groebner base w.r.t inverse lexicographical / target term order 197 */ 198 public List<GenPolynomial<C>> walkGroebnerToTarget(int modv, List<GenPolynomial<C>> Gl, 199 GenPolynomialRing<C> ufac) { 200 if (Gl == null || Gl.size() == 0) { 201 throw new IllegalArgumentException("G may not be null or empty"); 202 } 203 //Polynomial ring of input Groebner basis Gl 204 GenPolynomialRing<C> ring = Gl.get(0).ring; 205 if (debug) { 206 logger.info("ring = " + ring.toScript()); 207 } 208 //Polynomial ring of newGB with INVLEX / target term order 209 //TermOrder lexi = ufac.tord; //new TermOrder(TermOrder.INVLEX); 210 logger.info("G walk from ev1 = " + ring.tord.toScript() + " to ev2 = " + ufac.tord.toScript()); 211 List<GenPolynomial<C>> Giter = Gl; 212 // determine initial marks 213 List<ExpVector> marks = new ArrayList<ExpVector>(); 214 List<Monomial<C>> M = new ArrayList<Monomial<C>>(); 215 for (GenPolynomial<C> p : Giter) { 216 marks.add(p.leadingExpVector()); 217 M.add(new Monomial<C>(p.leadingMonomial())); 218 } 219 logger.info("marks = " + marks); 220 List<Monomial<C>> Mp = new ArrayList<Monomial<C>>(M); 221 // weight matrix for target term order 222 long[][] ufweight = TermOrderByName.weightForOrder(ufac.tord, ring.nvar); 223 //TermOrder word = TermOrder.reverseWeight(ufweight); 224 TermOrder word = new TermOrder(ufweight); 225 logger.info("weight order: " + word); 226 ufweight = word.getWeight(); // because of weightDeg usage 227 228 // loop throught term orders 229 ExpVector w = null; 230 int iter = 0; // count #loops 231 boolean done = false; 232 while (!done) { 233 iter++; 234 // determine V and w 235 PolynomialList<C> Pl = new PolynomialList<C>(ring, Giter); 236 SortedSet<ExpVector> delta = Pl.deltaExpVectors(marks); 237 //logger.info("delta(marks) = " + delta); 238 logger.info("w_old = " + w); 239 ExpVector v = facetNormal(ring.tord, ufac.tord, delta, ring.evzero, ufweight); 240 logger.info("minimal v = " + v); 241 if (v == null) { 242 done = true; 243 break; // finished 244 } 245 w = v; 246 // determine facet polynomials for w 247 List<GenPolynomial<C>> iG = new ArrayList<GenPolynomial<C>>(); 248 int i = 0; 249 for (GenPolynomial<C> f : Giter) { 250 ExpVector h = marks.get(i++); 251 GenPolynomial<C> ing = f.leadingFacetPolynomial(h, w); 252 if (debug) { 253 logger.info("ing_g = [" + ing + "], lt(ing) = " 254 + ing.ring.toScript(ing.leadingExpVector()) + ", f = " 255 + f.ring.toScript(f.leadingExpVector())); 256 } 257 iG.add(ing); 258 } 259 List<GenPolynomial<C>> inOmega = ufac.copy(iG); 260 if (debug) { 261 logger.info("inOmega = " + inOmega); 262 logger.info("inOmega.ring: " + inOmega.get(0).ring.toScript()); 263 } 264 265 // INVLEX / target term order GB of inOmega 266 List<GenPolynomial<C>> inOG = sgb.GB(modv, inOmega); 267 if (debug) { 268 logger.info("GB(inOmega) = " + inOG); 269 } 270 // remark polynomials 271 marks.clear(); 272 M.clear(); 273 for (GenPolynomial<C> p : inOG) { 274 marks.add(p.leadingExpVector()); 275 M.add(new Monomial<C>(p.leadingMonomial())); 276 } 277 logger.info("new marks/M = " + marks); 278 // lift and reduce 279 List<GenPolynomial<C>> G = liftReductas(M, Mp, Giter, inOG); 280 if (debug || (iter % iterPrint == 0)) { 281 logger.info("lift(" + iter + ") inOG, new GB: " + G); 282 } 283 if (G.size() == 1) { // will not happen 284 GenPolynomial<C> p = ufac.copy(G.get(0)); // change term order 285 G.clear(); 286 G.add(p); 287 return G; 288 } 289 // iterate 290 Giter = G; 291 Mp.clear(); 292 Mp.addAll(M); 293 } 294 return Giter; 295 } 296 297 298 /** 299 * Determine new facet normal. 300 * @param t1 old term order. 301 * @param t2 new term order. 302 * @param delta exponent vectors deltas. 303 * @param zero exponent vector. 304 * @param t2weight weight representation of t2. 305 * @return new facet normal v or null if no new facet normal exists. 306 */ 307 public ExpVector facetNormal(TermOrder t1, TermOrder t2, Set<ExpVector> delta, ExpVector zero, 308 long[][] t2weight) { 309 TermOrder.EVComparator ev1 = t1.getAscendComparator(); 310 TermOrder.EVComparator ev2 = t2.getAscendComparator(); 311 ExpVector v = null; 312 long d = 0; // = Long.MIN_VALUE; 313 for (ExpVector e : delta) { 314 if (ev1.compare(zero, e) >= 0 || ev2.compare(zero, e) <= 0) { //ring.evzero 315 //logger.info("skip e = " + e); 316 continue; 317 } 318 int s = 0; 319 long d2 = 0; 320 ExpVector vt = null; 321 ExpVector et = null; 322 if (v == null) { 323 v = e; 324 logger.info("init v = " + v); 325 continue; 326 } 327 for (long[] tau : t2weight) { 328 //logger.info("current tau = " + Arrays.toString(tau)); 329 //compare 330 d = v.weightDeg(tau); 331 d2 = e.weightDeg(tau); 332 vt = v.scalarMultiply(d2); 333 et = e.scalarMultiply(d); 334 s = ev1.compare(et, vt); 335 if (s == 0) { 336 continue; // next tau 337 } else if (s > 0) { // <, (> by example) 338 v = e; 339 break; 340 } else { 341 break; 342 } 343 } 344 //logger.info("step s = " + s + ", d = " + d + ", d2 = " + d2 + ", e = " + e); 345 // + ", v = " + v + ", et = " + et + ", vt = " + vt); 346 } 347 return v; 348 } 349 350 351 /** 352 * Cleanup and terminate ThreadPool. 353 */ 354 @Override 355 public void terminate() { 356 if (sgb == null) { 357 return; 358 } 359 sgb.terminate(); 360 } 361 362 363 /** 364 * Cancel ThreadPool. 365 */ 366 @Override 367 public int cancel() { 368 if (sgb == null) { 369 return 0; 370 } 371 return sgb.cancel(); 372 } 373 374 375 /** 376 * Lift leading polynomials to full Groebner base with respect to term 377 * order. 378 * @param M new leading monomial list of polynomials as marks. 379 * @param Mp old leading monomial list of polynomials as marks. 380 * @param G Groebner base polynomials for lift. 381 * @param A polynomial list of leading omega polynomials to lift. 382 * @return lift(A) a Groebner base wrt M of ideal(G). 383 */ 384 public List<GenPolynomial<C>> liftReductas(List<Monomial<C>> M, List<Monomial<C>> Mp, 385 List<GenPolynomial<C>> G, List<GenPolynomial<C>> A) { 386 if (G == null || M == null || Mp == null || G.isEmpty()) { 387 throw new IllegalArgumentException("null or empty lists not allowed"); 388 } 389 if (A == null || A.isEmpty()) { 390 return A; 391 } 392 if (G.size() != Mp.size() || A.size() != M.size()) { 393 throw new IllegalArgumentException("equal sized lists required"); 394 } 395 GenPolynomial<C> pol = G.get(0); 396 if (pol == null) { 397 throw new IllegalArgumentException("null polynomial not allowed"); 398 } 399 // remove mark monomials 400 List<GenPolynomial<C>> Gp = new ArrayList<GenPolynomial<C>>(G.size()); 401 int i = 0; 402 int len = G.size(); 403 for (i = 0; i < len; i++) { 404 Monomial<C> mon = Mp.get(i); 405 GenPolynomial<C> s = G.get(i).subtract(mon); 406 Gp.add(s); 407 } 408 if (debug) { 409 logger.info("lifter GB: Gp = " + Gp + ", Mp = " + Mp); 410 } 411 // compute f^Gp for f in A 412 //GenPolynomialRing<C> oring = pol.ring; 413 logger.info("liftReductas: G = " + G.size() + ", Mp = " + Mp.size()); // + ", old = " + oring.toScript()); 414 List<GenPolynomial<C>> Ap = A; //oring.copy(A); 415 //logger.info("to lift Ap = " + Ap); 416 ReductionAbstract<C> sred = (ReductionAbstract<C>) sgb.red; //new ReductionSeq<C>(); 417 List<GenPolynomial<C>> red = new ArrayList<GenPolynomial<C>>(); 418 GenPolynomialRing<C> tring = A.get(0).ring; 419 len = Ap.size(); 420 for (i = 0; i < len; i++) { 421 GenPolynomial<C> a = Ap.get(i); 422 GenPolynomial<C> r = sred.normalformMarked(Mp, Gp, a); 423 red.add(r); 424 } 425 logger.info("liftReductas: red(A) = " + red.size()); 426 // combine f - f^Gp in tring 427 if (debug) { 428 logger.info("tring = " + tring.toScript()); // + ", M = " + M); 429 } 430 List<GenPolynomial<C>> nb = new ArrayList<GenPolynomial<C>>(red.size()); 431 for (i = 0; i < A.size(); i++) { 432 GenPolynomial<C> x = tring.copy(A.get(i)); // Ap? A! 433 GenPolynomial<C> r = tring.copy(red.get(i)); 434 GenPolynomial<C> s = x.subtract(r); 435 Monomial<C> m = M.get(i); 436 s.doAddTo(m.coefficient().negate(), m.exponent()); // remove marked term 437 if (!s.coefficient(m.exponent()).isZERO()) { 438 System.out.println("L-M: x = " + x + ", r = " + r); 439 throw new IllegalArgumentException("mark not removed: " + s + ", m = " + m); 440 } 441 nb.add(s); 442 } 443 if (debug) { 444 logger.info("lifted-M, nb = " + nb.size()); 445 } 446 // minimal GB with preserved marks 447 //Collections.reverse(nb); // important for lex GB 448 len = nb.size(); 449 i = 0; 450 while (i < len) { 451 GenPolynomial<C> a = nb.remove(0); 452 Monomial<C> m = M.remove(0); // in step with element from nb 453 if (debug) { 454 logger.info("doing " + a + ", lt = " + tring.toScript(m.exponent())); 455 } 456 //a = sgb.red.normalform(nb, a); 457 a = sred.normalformMarked(M, nb, a); 458 if (debug) { 459 logger.info("done, a = " + a + ", lt = " + tring.toScript(a.leadingExpVector())); 460 } 461 nb.add(a); // adds as last 462 M.add(m); 463 i++; 464 } 465 // re-add mark after minimal 466 for (i = 0; i < len; i++) { 467 GenPolynomial<C> a = nb.get(i); 468 Monomial<C> m = M.get(i); 469 a.doAddTo(m.coefficient(), m.exponent()); // re-add marked term 470 nb.set(i, a); 471 } 472 logger.info("liftReductas: nb = " + nb.size() + ", M = " + M.size()); 473 //Collections.reverse(nb); // undo reverse 474 return nb; 475 } 476 477}