001/* 002 * $Id: GBAlgorithmBuilder.java 5773 2017-11-05 15:10:09Z kredel $ 003 */ 004 005package edu.jas.application; 006 007 008import java.io.Serializable; 009 010import org.apache.log4j.Logger; 011 012import edu.jas.arith.BigInteger; 013import edu.jas.arith.BigRational; 014import edu.jas.gb.GBOptimized; 015import edu.jas.gb.GBProxy; 016import edu.jas.gb.GroebnerBaseAbstract; 017import edu.jas.gb.GroebnerBaseParallel; 018import edu.jas.gb.GroebnerBaseSeqIter; 019import edu.jas.gb.GroebnerBaseF5zSigSeqIter; 020import edu.jas.gb.GroebnerBaseGGVSigSeqIter; 021import edu.jas.gb.GroebnerBaseArriSigSeqIter; 022import edu.jas.gb.GroebnerBaseParIter; 023import edu.jas.gb.OrderedMinPairlist; 024import edu.jas.gb.OrderedPairlist; 025import edu.jas.gb.OrderedSyzPairlist; 026import edu.jas.gb.PairList; 027import edu.jas.gbufd.GBFactory; 028import edu.jas.gbufd.GroebnerBaseFGLM; 029import edu.jas.gbufd.GroebnerBaseWalk; 030import edu.jas.gbufd.GroebnerBasePseudoParallel; 031import edu.jas.gbufd.GroebnerBaseQuotient; 032import edu.jas.gbufd.GroebnerBaseRational; 033import edu.jas.kern.ComputerThreads; 034import edu.jas.poly.GenPolynomial; 035import edu.jas.poly.GenPolynomialRing; 036import edu.jas.structure.GcdRingElem; 037import edu.jas.structure.RingFactory; 038import edu.jas.ufd.Quotient; 039import edu.jas.ufd.QuotientRing; 040 041 042/** 043 * Builder for commutative Gröbner bases algorithm implementations. 044 * @author Heinz Kredel 045 * @usage To create objects that implement the <code>GroebnerBase</code> 046 * interface one can use the <code>GBFactory</code> or this 047 * <code>GBAlgorithmBuilder</code>. This class will select and compose an 048 * appropriate implementation based on the types of polynomial 049 * coefficients C and the desired properties. To build an implementation 050 * start with the static method <code>polynomialRing()</code> to define 051 * the polynomial ring. Then continue to construct the algorithm with the 052 * methods 053 * <ul> 054 * <li><code>optimize()</code> or <code>optimize(boolean)</code> for term 055 * order (variable order) optimization (true for return of permuted 056 * polynomials),</li> 057 * <li><code>normalPairlist()</code> (default), 058 * <code>syzygyPairlist()</code> or <code>simplePairlist()</code> for 059 * pair-list selection strategies,</li> 060 * <li><code>fractionFree()</code> for clearing denominators and 061 * computing with pseudo reduction,</li> 062 * <li><code>graded()</code> for using the FGLM algorithm to first 063 * compute a Gröbner base with respect to a graded term order and 064 * then constructing a Gröbner base wrt. a lexicographical term 065 * order,</li> 066 * <li><code>walk()</code> for using the Gröbner walk algorithm to first 067 * compute a Gröbner base with respect to a graded term order and 068 * then constructing a Gröbner base wrt. a lexicographical term 069 * order,</li> 070 * <li><code>iterated()</code> for using the iterative GB algorithm to 071 * compute a Gröbner base adding one polynomial after another,</li> 072 * <li><code>F5()</code>, <code>GGV()</code> and <code>Arri()</code> for using 073 * the respective iterative signature based GB algorithm (over field coefficients) to 074 * compute a Gröbner base adding one polynomial after another,</li> 075 * <li><code>parallel()</code> additionaly compute a Gröbner base 076 * over a field or integral domain in parallel,</li> 077 * <li><code>euclideanDomain()</code> for computing a e-Gröbner 078 * base,</li> 079 * <li><code>domainAlgorithm(Algo)</code> for computing a d- or 080 * e-Gröbner base,</li> 081 * </ul> 082 * Finally call the method <code>build()</code> to obtain an 083 * implementaton of class <code>GroebnerBaseAbstract</code>. For example 084 * 085 * <pre> 086 * 087 * GenPolynomialRing<C> pf = new GenPolynomialRing<C>(cofac, vars); 088 * GroebnerBaseAbstract<C> engine; 089 * engine = GBAlgorithmBuilder.<C> polynomialRing(pf).fractionFree().parallel().optimize().build(); 090 * c = engine.GB(A); 091 * </pre> 092 * 093 * For example, if the coefficient type is BigRational, the usage looks 094 * like 095 * 096 * <pre> 097 * 098 * GenPolynomialRing<BigRational> pf = new GenPolynomialRing<BigRational>(cofac, vars); 099 * GroebnerBaseAbstract<BigRational> engine; 100 * engine = GBAlgorithmBuilder.<BigRational> polynomialRing(pf).fractionFree().parallel().optimize().build(); 101 * c = engine.GB(A); 102 * </pre> 103 * 104 * <b>Note:</b> Not all combinations are meanigful 105 * 106 * @see edu.jas.gb.GroebnerBase 107 * @see edu.jas.gbufd.GBFactory 108 */ 109 110public class GBAlgorithmBuilder<C extends GcdRingElem<C>> implements Serializable { 111 112 113 private static final Logger logger = Logger.getLogger(GBAlgorithmBuilder.class); 114 115 116 /** 117 * The current GB algorithm implementation. 118 */ 119 private GroebnerBaseAbstract<C> algo; 120 121 122 /** 123 * The current polynomial ring. 124 */ 125 public final GenPolynomialRing<C> ring; 126 127 128 /** 129 * Requested pairlist strategy. 130 */ 131 public final PairList<C> strategy; 132 133 134 /** 135 * Constructor not for use. 136 */ 137 protected GBAlgorithmBuilder() { 138 throw new IllegalArgumentException("do not use this constructor"); 139 } 140 141 142 /** 143 * Constructor. 144 * @param ring the polynomial ring. 145 */ 146 public GBAlgorithmBuilder(GenPolynomialRing<C> ring) { 147 this(ring, null); 148 } 149 150 151 /** 152 * Constructor. 153 * @param ring the polynomial ring. 154 * @param algo already determined algorithm. 155 */ 156 public GBAlgorithmBuilder(GenPolynomialRing<C> ring, GroebnerBaseAbstract<C> algo) { 157 this(ring, algo, null); 158 } 159 160 161 /** 162 * Constructor. 163 * @param ring the polynomial ring. 164 * @param algo already determined algorithm. 165 * @param strategy pairlist strategy. 166 */ 167 public GBAlgorithmBuilder(GenPolynomialRing<C> ring, GroebnerBaseAbstract<C> algo, PairList<C> strategy) { 168 if (ring == null) { 169 throw new IllegalArgumentException("ring may not be null"); 170 } 171 this.ring = ring; 172 if (strategy == null) { 173 strategy = new OrderedPairlist<C>(); 174 } else { 175 if (algo == null) { // or overwrite? 176 algo = GBFactory.<C> getImplementation(ring.coFac, strategy); 177 } 178 } 179 this.algo = algo; // null accepted 180 this.strategy = strategy; 181 } 182 183 184 /** 185 * Build the GB algorithm implementaton. 186 * @return GB algorithm implementaton as GroebnerBaseAbstract object. 187 */ 188 public GroebnerBaseAbstract<C> build() { 189 if (algo == null) { 190 if (strategy == null) { // should not happen 191 algo = GBFactory.<C> getImplementation(ring.coFac); 192 } else { 193 algo = GBFactory.<C> getImplementation(ring.coFac, strategy); 194 } 195 } 196 return algo; 197 } 198 199 200 /** 201 * Define polynomial ring. 202 * @param fac the commutative polynomial ring. 203 * @return GBAlgorithmBuilder object. 204 */ 205 public static <C extends GcdRingElem<C>> GBAlgorithmBuilder<C> polynomialRing(GenPolynomialRing<C> fac) { 206 return new GBAlgorithmBuilder<C>(fac); 207 } 208 209 210 /** 211 * Select syzygy critical pair-list strategy. Gebauer and Möller 212 * algorithm. 213 * @return GBAlgorithmBuilder object. 214 */ 215 public GBAlgorithmBuilder<C> syzygyPairlist() { 216 return new GBAlgorithmBuilder<C>(ring, algo, new OrderedSyzPairlist<C>()); 217 } 218 219 220 /** 221 * Select normal critical pair-list strategy. Buchberger, Winkler and Kredel 222 * algorithm. 223 * @return GBAlgorithmBuilder object. 224 */ 225 public GBAlgorithmBuilder<C> normalPairlist() { 226 return new GBAlgorithmBuilder<C>(ring, algo, new OrderedPairlist<C>()); 227 } 228 229 230 /** 231 * Select simple critical pair-list strategy. Original Buchberger algorithm. 232 * @return GBAlgorithmBuilder object. 233 */ 234 public GBAlgorithmBuilder<C> simplePairlist() { 235 return new GBAlgorithmBuilder<C>(ring, algo, new OrderedMinPairlist<C>()); 236 } 237 238 239 /** 240 * Request term order optimization. Call optimize(true) for return of 241 * permuted polynomials. 242 * @return GBAlgorithmBuilder object. 243 */ 244 public GBAlgorithmBuilder<C> optimize() { 245 return optimize(true); 246 } 247 248 249 /** 250 * Request term order optimization. 251 * @param rP true for return of permuted polynomials, false for inverse 252 * permuted polynomials and new GB computation. 253 * @return GBAlgorithmBuilder object. 254 */ 255 public GBAlgorithmBuilder<C> optimize(boolean rP) { 256 if (algo == null) { 257 algo = GBFactory.<C> getImplementation(ring.coFac, strategy); 258 } 259 GroebnerBaseAbstract<C> bb = new GBOptimized<C>(algo, rP); 260 return new GBAlgorithmBuilder<C>(ring, bb, strategy); 261 } 262 263 264 /** 265 * Request fraction free algorithm. For BigRational and Quotient 266 * coefficients denominators are cleared and pseudo reduction is used. 267 * @return GBAlgorithmBuilder object. 268 */ 269 @SuppressWarnings({"cast", "unchecked"}) 270 public GBAlgorithmBuilder<C> fractionFree() { 271 if (algo != null) { 272 logger.warn("selected algorithm ignored: " + algo + ", use fractionFree before"); 273 } 274 if (((Object) ring.coFac) instanceof BigRational) { 275 BigRational cf = (BigRational) (Object) ring.coFac; 276 PairList<BigRational> sty = (PairList) strategy; 277 GroebnerBaseAbstract<BigRational> bb = GBFactory.getImplementation(cf, GBFactory.Algo.ffgb, sty); 278 GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb; 279 return new GBAlgorithmBuilder<C>(ring, cbb, strategy); 280 } 281 if (((Object) ring.coFac) instanceof QuotientRing) { 282 QuotientRing<C> cf = (QuotientRing<C>) (Object) ring.coFac; 283 PairList<Quotient<C>> sty = (PairList) strategy; 284 GroebnerBaseAbstract<Quotient<C>> bb = GBFactory.<C> getImplementation(cf, GBFactory.Algo.ffgb, 285 sty); 286 GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb; 287 return new GBAlgorithmBuilder<C>(ring, cbb, strategy); 288 } 289 logger.warn("no fraction free algorithm implemented for " + ring); 290 return this; 291 } 292 293 294 /** 295 * Request e-GB algorithm. 296 * @return GBAlgorithmBuilder object. 297 */ 298 public GBAlgorithmBuilder<C> euclideanDomain() { 299 return domainAlgorithm(GBFactory.Algo.egb); 300 } 301 302 303 /** 304 * Request d-, e- or i-GB algorithm. 305 * @param a algorithm from GBFactory.Algo. 306 * @return GBAlgorithmBuilder object. 307 */ 308 @SuppressWarnings({"cast", "unchecked"}) 309 public GBAlgorithmBuilder<C> domainAlgorithm(GBFactory.Algo a) { 310 if (strategy != null) { 311 logger.warn("strategy " + strategy + " ignored for algorithm " + a); 312 } 313 if (((Object) ring.coFac) instanceof BigInteger) { 314 BigInteger cf = (BigInteger) (Object) ring.coFac; 315 GroebnerBaseAbstract<BigInteger> bb = GBFactory.getImplementation(cf, a); 316 GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb; 317 return new GBAlgorithmBuilder<C>(ring, cbb); 318 } 319 if (((Object) ring.coFac) instanceof GenPolynomial) { 320 GenPolynomialRing<C> cf = (GenPolynomialRing) (Object) ring.coFac; 321 GroebnerBaseAbstract<GenPolynomial<C>> bb = GBFactory.<C> getImplementation(cf, a); 322 GroebnerBaseAbstract<C> cbb = (GroebnerBaseAbstract<C>) (GroebnerBaseAbstract) bb; 323 return new GBAlgorithmBuilder<C>(ring, cbb); 324 } 325 logger.warn("no domain algorithm implemented for " + ring); 326 return this; 327 } 328 329 330 /** 331 * Request parallel algorithm. Additionaly run a parallel algorithm via 332 * GBProxy. 333 * @return GBAlgorithmBuilder object. 334 */ 335 @SuppressWarnings("unchecked") 336 public GBAlgorithmBuilder<C> parallel() { 337 return parallel(ComputerThreads.N_CPUS); 338 } 339 340 341 /** 342 * Request parallel algorithm. Additionaly run a parallel algorithm via 343 * GBProxy. 344 * @param threads number of threads requested. 345 * @return GBAlgorithmBuilder object. 346 */ 347 @SuppressWarnings({"cast", "unchecked"}) 348 public GBAlgorithmBuilder<C> parallel(int threads) { 349 if (ComputerThreads.NO_THREADS) { 350 logger.warn("parallel algorithms disabled"); 351 return this; 352 } 353 if (algo == null) { 354 algo = GBFactory.<C> getImplementation(ring.coFac, strategy); 355 } 356 if (algo instanceof GroebnerBaseSeqIter) { // iterative requested 357 GroebnerBaseAbstract<C> bb; 358 bb = (GroebnerBaseAbstract) new GroebnerBaseParIter<C>(threads, strategy); 359 GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb); 360 return new GBAlgorithmBuilder<C>(ring, pbb, strategy); 361 } else if (((RingFactory) ring.coFac) instanceof BigRational) { 362 GroebnerBaseAbstract<C> bb; 363 if (algo instanceof GroebnerBaseRational) { // fraction free requested 364 PairList<BigInteger> pli; 365 if (strategy instanceof OrderedMinPairlist) { 366 pli = new OrderedMinPairlist<BigInteger>(); 367 } else if (strategy instanceof OrderedSyzPairlist) { 368 pli = new OrderedSyzPairlist<BigInteger>(); 369 } else { 370 pli = new OrderedPairlist<BigInteger>(); 371 } 372 bb = (GroebnerBaseAbstract) new GroebnerBaseRational<BigRational>(threads, pli); 373 } else { 374 bb = (GroebnerBaseAbstract) new GroebnerBaseParallel<C>(threads, strategy); 375 } 376 GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb); 377 return new GBAlgorithmBuilder<C>(ring, pbb, strategy); 378 } else if (((RingFactory) ring.coFac) instanceof QuotientRing) { 379 GroebnerBaseAbstract<C> bb; 380 if (algo instanceof GroebnerBaseQuotient) { // fraction free requested 381 PairList<GenPolynomial<C>> pli; 382 if (strategy instanceof OrderedMinPairlist) { 383 pli = new OrderedMinPairlist<GenPolynomial<C>>(); 384 } else if (strategy instanceof OrderedSyzPairlist) { 385 pli = new OrderedSyzPairlist<GenPolynomial<C>>(); 386 } else { 387 pli = new OrderedPairlist<GenPolynomial<C>>(); 388 } 389 QuotientRing<C> fac = (QuotientRing) ring.coFac; 390 bb = (GroebnerBaseAbstract) new GroebnerBaseQuotient<C>(threads, fac, pli); // pl not possible 391 } else { 392 bb = (GroebnerBaseAbstract) new GroebnerBaseParallel<C>(threads, strategy); 393 } 394 GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb); 395 return new GBAlgorithmBuilder<C>(ring, pbb); 396 } else if (ring.coFac.isField()) { 397 GroebnerBaseAbstract<C> bb = new GroebnerBaseParallel<C>(threads, strategy); 398 GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb); 399 return new GBAlgorithmBuilder<C>(ring, pbb, strategy); 400 } else if (ring.coFac.getONE() instanceof GcdRingElem) { 401 GroebnerBaseAbstract<C> bb = new GroebnerBasePseudoParallel<C>(threads, ring.coFac, strategy); 402 GroebnerBaseAbstract<C> pbb = new GBProxy<C>(algo, bb); 403 return new GBAlgorithmBuilder<C>(ring, pbb, strategy); 404 } 405 logger.warn("no parallel algorithm implemented for " + ring); 406 return this; 407 } 408 409 410 /** 411 * Request FGLM algorithm. 412 * @return GBAlgorithmBuilder object. 413 */ 414 @SuppressWarnings("unchecked") 415 public GBAlgorithmBuilder<C> graded() { 416 if (ring.coFac.isField()) { 417 GroebnerBaseAbstract<C> bb; 418 if (algo == null) { 419 bb = new GroebnerBaseFGLM<C>(); 420 } else { 421 bb = new GroebnerBaseFGLM<C>(algo); 422 } 423 return new GBAlgorithmBuilder<C>(ring, bb, strategy); 424 } 425 logger.warn("no FGLM algorithm implemented for " + ring); 426 return this; 427 } 428 429 430 /** 431 * Request Groebner walk algorithm. 432 * @return GBAlgorithmBuilder object. 433 */ 434 @SuppressWarnings("unchecked") 435 public GBAlgorithmBuilder<C> walk() { 436 if (ring.coFac.isField()) { 437 GroebnerBaseAbstract<C> bb; 438 if (algo == null) { 439 bb = new GroebnerBaseWalk<C>(); 440 } else { 441 bb = new GroebnerBaseWalk<C>(algo); 442 } 443 return new GBAlgorithmBuilder<C>(ring, bb, strategy); 444 } 445 logger.warn("no Groebner walk algorithm implemented for " + ring); 446 return this; 447 } 448 449 450 /** 451 * Request iterated GB algorithm. 452 * @return GBAlgorithmBuilder object. 453 */ 454 @SuppressWarnings("unchecked") 455 public GBAlgorithmBuilder<C> iterated() { 456 if (ring.coFac.isField()) { 457 GroebnerBaseAbstract<C> bb; 458 bb = new GroebnerBaseSeqIter<C>(strategy); 459 // if (algo instanceof GBProxy) ... assemble parallel todo 460 if (algo != null) { 461 logger.warn("algorithm " + algo + " ignored for " + bb); 462 } 463 return new GBAlgorithmBuilder<C>(ring, bb, strategy); 464 } 465 logger.warn("no iterated GB algorithm implemented for " + ring); 466 return this; 467 } 468 469 470 /** 471 * Request iterated F5 signature based GB algorithm. 472 * @return GBAlgorithmBuilder object. 473 */ 474 @SuppressWarnings("unchecked") 475 public GBAlgorithmBuilder<C> F5() { 476 if (ring.coFac.isField()) { 477 GroebnerBaseAbstract<C> bb; 478 bb = new GroebnerBaseF5zSigSeqIter<C>(); 479 // if (algo instanceof GBProxy) ... assemble parallel todo 480 if (algo != null) { 481 logger.warn("algorithm " + algo + " ignored for " + bb); 482 } 483 if (strategy != null) { 484 logger.warn("strategy " + strategy + " ignored for " + bb); 485 } 486 return new GBAlgorithmBuilder<C>(ring, bb, strategy); 487 } 488 logger.warn("no iterated F5 GB algorithm implemented for " + ring); 489 return this; 490 } 491 492 493 /** 494 * Request iterated GGV signature based GB algorithm. 495 * @return GBAlgorithmBuilder object. 496 */ 497 @SuppressWarnings("unchecked") 498 public GBAlgorithmBuilder<C> GGV() { 499 if (ring.coFac.isField()) { 500 GroebnerBaseAbstract<C> bb; 501 bb = new GroebnerBaseGGVSigSeqIter<C>(); 502 // if (algo instanceof GBProxy) ... assemble parallel todo 503 if (algo != null) { 504 logger.warn("algorithm " + algo + " ignored for " + bb); 505 } 506 if (strategy != null) { 507 logger.warn("strategy " + strategy + " ignored for " + bb); 508 } 509 return new GBAlgorithmBuilder<C>(ring, bb, strategy); 510 } 511 logger.warn("no iterated GGV GB algorithm implemented for " + ring); 512 return this; 513 } 514 515 516 /** 517 * Request iterated Arri signature based GB algorithm. 518 * @return GBAlgorithmBuilder object. 519 */ 520 @SuppressWarnings("unchecked") 521 public GBAlgorithmBuilder<C> Arri() { 522 if (ring.coFac.isField()) { 523 GroebnerBaseAbstract<C> bb; 524 bb = new GroebnerBaseArriSigSeqIter<C>(); 525 // if (algo instanceof GBProxy) ... assemble parallel todo 526 if (algo != null) { 527 logger.warn("algorithm " + algo + " ignored for " + bb); 528 } 529 if (strategy != null) { 530 logger.warn("strategy " + strategy + " ignored for " + bb); 531 } 532 return new GBAlgorithmBuilder<C>(ring, bb, strategy); 533 } 534 logger.warn("no iterated Arri GB algorithm implemented for " + ring); 535 return this; 536 } 537 538 539 /** 540 * String representation of the GB algorithm implementation. 541 * @see java.lang.Object#toString() 542 */ 543 @Override 544 public String toString() { 545 StringBuffer s = new StringBuffer(" "); 546 if (algo != null) { 547 s.append(algo.toString()); 548 s.append(" for "); 549 } 550 s.append(ring.toString()); 551 if (strategy != null) { 552 s.append(" strategy="); 553 s.append(strategy.toString()); 554 } 555 return s.toString(); 556 } 557 558 559 /** 560 * Get a scripting compatible string representation. 561 * @return script compatible representation for this Element. 562 * @see edu.jas.structure.Element#toScript() 563 */ 564 public String toScript() { 565 // Python case 566 StringBuffer s = new StringBuffer(" "); 567 if (algo != null) { 568 s.append(algo.toString()); // nonsense 569 s.append(" "); 570 } 571 s.append(ring.toScript()); 572 if (strategy != null) { 573 s.append(",strategy="); 574 s.append(strategy.toString()); 575 } 576 return s.toString(); 577 } 578 579}