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