001/* 002 * $Id: GroebnerBasePseudoRecParallel.java 5870 2018-07-20 15:56:23Z kredel $ 003 */ 004 005package edu.jas.gbufd; 006 007 008import java.util.ArrayList; 009import java.util.Collections; 010import java.util.List; 011import java.util.concurrent.Semaphore; 012 013import org.apache.logging.log4j.Logger; 014import org.apache.logging.log4j.LogManager; 015 016import edu.jas.gb.GroebnerBaseAbstract; 017import edu.jas.gb.OrderedPairlist; 018import edu.jas.gb.Pair; 019import edu.jas.gb.PairList; 020import edu.jas.poly.ExpVector; 021import edu.jas.poly.GenPolynomial; 022import edu.jas.poly.GenPolynomialRing; 023import edu.jas.structure.GcdRingElem; 024import edu.jas.structure.RingFactory; 025import edu.jas.ufd.GCDFactory; 026import edu.jas.ufd.GreatestCommonDivisorAbstract; 027import edu.jas.util.Terminator; 028import edu.jas.util.ThreadPool; 029 030 031/** 032 * Groebner Base with recursive pseudo reduction multi-threaded parallel 033 * algorithm. Implements coefficient fraction free Groebner bases. 034 * Coefficients can for example be (commutative) multivariate polynomials. 035 * @param <C> coefficient type 036 * @author Heinz Kredel 037 * 038 * @see edu.jas.application.GBAlgorithmBuilder 039 * @see edu.jas.gbufd.GBFactory 040 */ 041 042public class GroebnerBasePseudoRecParallel<C extends GcdRingElem<C>> extends 043 GroebnerBaseAbstract<GenPolynomial<C>> { 044 045 046 private static final Logger logger = LogManager.getLogger(GroebnerBasePseudoRecParallel.class); 047 048 049 private static final boolean debug = logger.isDebugEnabled(); 050 051 052 /** 053 * Number of threads to use. 054 */ 055 protected final int threads; 056 057 058 /** 059 * Pool of threads to use. 060 */ 061 protected transient final ThreadPool pool; 062 063 064 /** 065 * Greatest common divisor engine for coefficient content and primitive 066 * parts. 067 */ 068 protected final GreatestCommonDivisorAbstract<C> engine; 069 070 071 /** 072 * Pseudo reduction engine. 073 */ 074 protected final PseudoReduction<C> redRec; 075 076 077 /** 078 * Pseudo reduction engine. 079 */ 080 protected final PseudoReduction<GenPolynomial<C>> red; 081 082 083 /** 084 * Coefficient ring factory. 085 */ 086 protected final RingFactory<GenPolynomial<C>> cofac; 087 088 089 /** 090 * Base coefficient ring factory. 091 */ 092 protected final RingFactory<C> baseCofac; 093 094 095 /** 096 * Constructor. 097 * @param threads number of threads to use. 098 * @param rf coefficient ring factory. 099 */ 100 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf) { 101 this(threads, rf, new PseudoReductionPar<GenPolynomial<C>>(), new ThreadPool(threads), 102 new OrderedPairlist<GenPolynomial<C>>(new GenPolynomialRing<GenPolynomial<C>>(rf, 1))); // 1=hack 103 } 104 105 106 /** 107 * Constructor. 108 * @param threads number of threads to use. 109 * @param rf coefficient ring factory. <b>Note:</b> red must be an instance 110 * of PseudoReductionPar. 111 * @param red pseudo reduction engine. 112 */ 113 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf, 114 PseudoReduction<GenPolynomial<C>> red) { 115 this(threads, rf, red, new ThreadPool(threads)); 116 } 117 118 119 /** 120 * Constructor. 121 * @param threads number of threads to use. 122 * @param rf coefficient ring factory. <b>Note:</b> red must be an instance 123 * of PseudoReductionPar. 124 * @param red pseudo reduction engine. 125 * @param pool ThreadPool to use. 126 */ 127 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf, 128 PseudoReduction<GenPolynomial<C>> red, ThreadPool pool) { 129 this(threads, rf, red, pool, new OrderedPairlist<GenPolynomial<C>>( 130 new GenPolynomialRing<GenPolynomial<C>>(rf, 1))); // 1=hack 131 } 132 133 134 /** 135 * Constructor. 136 * @param threads number of threads to use. 137 * @param rf coefficient ring factory. <b>Note:</b> red must be an instance 138 * of PseudoReductionPar. 139 * @param pl pair selection strategy 140 */ 141 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf, 142 PairList<GenPolynomial<C>> pl) { 143 this(threads, rf, new PseudoReductionPar<GenPolynomial<C>>(), new ThreadPool(threads), pl); 144 } 145 146 147 /** 148 * Constructor. 149 * @param threads number of threads to use. 150 * @param rf coefficient ring factory. <b>Note:</b> red must be an instance 151 * of PseudoReductionPar. 152 * @param red pseudo reduction engine. 153 * @param pool ThreadPool to use. 154 * @param pl pair selection strategy 155 */ 156 @SuppressWarnings("unchecked") 157 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf, 158 PseudoReduction<GenPolynomial<C>> red, ThreadPool pool, PairList<GenPolynomial<C>> pl) { 159 super(red, pl); 160 if (!(red instanceof PseudoReductionPar)) { 161 logger.warn("parallel GB should use parallel aware reduction"); 162 } 163 this.red = red; 164 this.redRec = (PseudoReduction<C>) (PseudoReduction) red; 165 cofac = rf; 166 if (threads < 1) { 167 threads = 1; 168 } 169 this.threads = threads; 170 GenPolynomialRing<C> rp = (GenPolynomialRing<C>) cofac; 171 baseCofac = rp.coFac; 172 //engine = (GreatestCommonDivisorAbstract<C>)GCDFactory.<C>getImplementation( baseCofac ); 173 //not used: 174 engine = GCDFactory.<C> getProxy(baseCofac); 175 this.pool = pool; 176 } 177 178 179 /** 180 * Cleanup and terminate ThreadPool. 181 */ 182 @Override 183 public void terminate() { 184 if (pool == null) { 185 return; 186 } 187 pool.terminate(); 188 } 189 190 191 /** 192 * Cancel ThreadPool. 193 */ 194 @Override 195 public int cancel() { 196 if (pool == null) { 197 return 0; 198 } 199 int s = pool.cancel(); 200 return s; 201 } 202 203 204 /** 205 * Groebner base using pairlist class. 206 * @param modv module variable number. 207 * @param F polynomial list. 208 * @return GB(F) a Groebner base of F. 209 */ 210 public List<GenPolynomial<GenPolynomial<C>>> GB(int modv, List<GenPolynomial<GenPolynomial<C>>> F) { 211 List<GenPolynomial<GenPolynomial<C>>> G = normalizeZerosOnes(F); 212 G = engine.recursivePrimitivePart(G); 213 if (G.size() <= 1) { 214 return G; 215 } 216 GenPolynomialRing<GenPolynomial<C>> ring = G.get(0).ring; 217 if (ring.coFac.isField()) { // remove ? 218 throw new IllegalArgumentException("coefficients from a field"); 219 } 220 PairList<GenPolynomial<C>> pairlist = strategy.create(modv, ring); 221 pairlist.put(G); 222 logger.info("start " + pairlist); 223 224 Terminator fin = new Terminator(threads); 225 PseudoReducerRec<C> R; 226 for (int i = 0; i < threads; i++) { 227 R = new PseudoReducerRec<C>(fin, G, pairlist, engine); 228 pool.addJob(R); 229 } 230 fin.waitDone(); 231 if (Thread.currentThread().isInterrupted()) { 232 throw new RuntimeException("interrupt before minimalGB"); 233 } 234 logger.debug("#parallel list = " + G.size()); 235 G = minimalGB(G); 236 logger.info("" + pairlist); 237 return G; 238 } 239 240 241 /** 242 * Minimal ordered Groebner basis. 243 * @param Gp a Groebner base. 244 * @return a reduced Groebner base of Gp. 245 */ 246 @Override 247 public List<GenPolynomial<GenPolynomial<C>>> minimalGB(List<GenPolynomial<GenPolynomial<C>>> Gp) { 248 List<GenPolynomial<GenPolynomial<C>>> G = normalizeZerosOnes(Gp); 249 if (G.size() <= 1) { 250 return G; 251 } 252 // remove top reducible polynomials 253 GenPolynomial<GenPolynomial<C>> a; 254 List<GenPolynomial<GenPolynomial<C>>> F; 255 F = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size()); 256 while (G.size() > 0) { 257 a = G.remove(0); 258 if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { 259 // drop polynomial 260 if (debug) { 261 System.out.println("dropped " + a); 262 List<GenPolynomial<GenPolynomial<C>>> ff; 263 ff = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G); 264 ff.addAll(F); 265 //a = red.normalform(ff, a); 266 a = redRec.normalformRecursive(ff, a); 267 if (!a.isZERO()) { 268 System.out.println("error, nf(a) " + a); 269 } 270 } 271 } else { 272 F.add(a); 273 } 274 } 275 G = F; 276 if (G.size() <= 1) { 277 return G; 278 } 279 Collections.reverse(G); // important for lex GB 280 // reduce remaining polynomials 281 @SuppressWarnings("unchecked") 282 PseudoMiReducerRec<C>[] mirs = (PseudoMiReducerRec<C>[]) new PseudoMiReducerRec[G.size()]; 283 int i = 0; 284 F = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size()); 285 while (G.size() > 0) { 286 a = G.remove(0); 287 List<GenPolynomial<GenPolynomial<C>>> R = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size() 288 + F.size()); 289 R.addAll(G); 290 R.addAll(F); 291 // System.out.println("doing " + a.length()); 292 mirs[i] = new PseudoMiReducerRec<C>(R, a, engine); 293 pool.addJob(mirs[i]); 294 i++; 295 F.add(a); 296 } 297 G = F; 298 F = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size()); 299 for (i = 0; i < mirs.length; i++) { 300 a = mirs[i].getNF(); 301 F.add(a); 302 } 303 Collections.reverse(F); // undo reverse 304 return F; 305 } 306 307 308 /** 309 * Groebner base simple test. 310 * @param modv module variable number. 311 * @param F recursive polynomial list. 312 * @return true, if F is a Groebner base, else false. 313 */ 314 @Override 315 public boolean isGBsimple(int modv, List<GenPolynomial<GenPolynomial<C>>> F) { 316 if (F == null || F.isEmpty()) { 317 return true; 318 } 319 GenPolynomial<GenPolynomial<C>> pi, pj, s, h; 320 ExpVector ei, ej, eij; 321 for (int i = 0; i < F.size(); i++) { 322 pi = F.get(i); 323 ei = pi.leadingExpVector(); 324 for (int j = i + 1; j < F.size(); j++) { 325 pj = F.get(j); 326 ej = pj.leadingExpVector(); 327 if (!red.moduleCriterion(modv, ei, ej)) { 328 continue; 329 } 330 eij = ei.lcm(ej); 331 if (!red.criterion4(ei, ej, eij)) { 332 continue; 333 } 334 //if (!criterion3(i, j, eij, F)) { 335 // continue; 336 //} 337 s = red.SPolynomial(pi, pj); 338 if (s.isZERO()) { 339 continue; 340 } 341 //System.out.println("i, j = " + i + ", " + j); 342 h = redRec.normalformRecursive(F, s); 343 if (!h.isZERO()) { 344 logger.info("no GB: pi = " + pi + ", pj = " + pj); 345 logger.info("s = " + s + ", h = " + h); 346 return false; 347 } 348 } 349 } 350 return true; 351 } 352 353} 354 355 356/** 357 * Pseudo GB Reducing worker threads. 358 */ 359class PseudoReducerRec<C extends GcdRingElem<C>> implements Runnable { 360 361 362 private final List<GenPolynomial<GenPolynomial<C>>> G; 363 364 365 private final PairList<GenPolynomial<C>> pairlist; 366 367 368 private final Terminator fin; 369 370 371 private final PseudoReductionPar<GenPolynomial<C>> red; 372 373 374 private final PseudoReductionPar<C> redRec; 375 376 377 private final GreatestCommonDivisorAbstract<C> engine; 378 379 380 private static final Logger logger = LogManager.getLogger(PseudoReducerRec.class); 381 382 383 PseudoReducerRec(Terminator fin, List<GenPolynomial<GenPolynomial<C>>> G, PairList<GenPolynomial<C>> L, 384 GreatestCommonDivisorAbstract<C> engine) { 385 this.fin = fin; 386 this.G = G; 387 pairlist = L; 388 red = new PseudoReductionPar<GenPolynomial<C>>(); 389 redRec = new PseudoReductionPar<C>(); 390 this.engine = engine; 391 fin.initIdle(1); 392 } 393 394 395 /** 396 * to string 397 */ 398 @Override 399 public String toString() { 400 return "PseudoReducer"; 401 } 402 403 404 public void run() { 405 Pair<GenPolynomial<C>> pair; 406 GenPolynomial<GenPolynomial<C>> pi, pj, S, H; 407 //boolean set = false; 408 int reduction = 0; 409 int sleeps = 0; 410 while (pairlist.hasNext() || fin.hasJobs()) { 411 while (!pairlist.hasNext()) { 412 // wait 413 //fin.beIdle(); set = true; 414 try { 415 sleeps++; 416 if (sleeps % 10 == 0) { 417 logger.info(" reducer is sleeping"); 418 } else { 419 logger.debug("r"); 420 } 421 Thread.sleep(100); 422 } catch (InterruptedException e) { 423 break; 424 } 425 if (!fin.hasJobs()) { 426 break; 427 } 428 } 429 if (!pairlist.hasNext() && !fin.hasJobs()) { 430 break; 431 } 432 433 fin.notIdle(); // before pairlist get 434 pair = pairlist.removeNext(); 435 if (Thread.currentThread().isInterrupted()) { 436 fin.initIdle(1); 437 throw new RuntimeException("interrupt after removeNext"); 438 } 439 if (pair == null) { 440 fin.initIdle(1); 441 continue; 442 } 443 444 pi = pair.pi; 445 pj = pair.pj; 446 if (logger.isDebugEnabled()) { 447 logger.debug("pi = " + pi); 448 logger.debug("pj = " + pj); 449 } 450 451 S = red.SPolynomial(pi, pj); 452 if (S.isZERO()) { 453 pair.setZero(); 454 fin.initIdle(1); 455 continue; 456 } 457 if (logger.isDebugEnabled()) { 458 logger.debug("ht(S) = " + S.leadingExpVector()); 459 } 460 461 //H = red.normalform(G, S); //mod 462 H = redRec.normalformRecursive(G, S); 463 reduction++; 464 if (H.isZERO()) { 465 pair.setZero(); 466 fin.initIdle(1); 467 continue; 468 } 469 if (logger.isDebugEnabled()) { 470 logger.info("ht(H) = " + H.leadingExpVector()); 471 } 472 473 H = engine.recursivePrimitivePart(H); //H.monic(); 474 H = H.abs(); 475 // System.out.println("H = " + H); 476 if (H.isONE()) { 477 // putOne not required 478 pairlist.put(H); 479 synchronized (G) { 480 G.clear(); 481 G.add(H); 482 } 483 fin.allIdle(); 484 return; 485 } 486 if (logger.isDebugEnabled()) { 487 logger.debug("H = " + H); 488 } 489 synchronized (G) { 490 G.add(H); 491 } 492 pairlist.put(H); 493 fin.initIdle(1); 494 } 495 fin.allIdle(); 496 logger.info("terminated, done " + reduction + " reductions"); 497 } 498} 499 500 501/** 502 * Pseudo Reducing worker threads for minimal GB. 503 */ 504class PseudoMiReducerRec<C extends GcdRingElem<C>> implements Runnable { 505 506 507 private final List<GenPolynomial<GenPolynomial<C>>> G; 508 509 510 private GenPolynomial<GenPolynomial<C>> H; 511 512 513 //private final PseudoReductionPar<GenPolynomial<C>> red; 514 515 516 private final PseudoReductionPar<C> redRec; 517 518 519 private final Semaphore done = new Semaphore(0); 520 521 522 private final GreatestCommonDivisorAbstract<C> engine; 523 524 525 private static final Logger logger = LogManager.getLogger(PseudoMiReducerRec.class); 526 527 528 PseudoMiReducerRec(List<GenPolynomial<GenPolynomial<C>>> G, GenPolynomial<GenPolynomial<C>> p, 529 GreatestCommonDivisorAbstract<C> engine) { 530 this.G = G; 531 this.engine = engine; 532 H = p; 533 //red = new PseudoReductionPar<GenPolynomial<C>>(); 534 redRec = new PseudoReductionPar<C>(); 535 } 536 537 538 /** 539 * to string 540 */ 541 @Override 542 public String toString() { 543 return "PseudoMiReducerRec"; 544 } 545 546 547 /** 548 * getNF. Blocks until the normal form is computed. 549 * @return the computed normal form. 550 */ 551 public GenPolynomial<GenPolynomial<C>> getNF() { 552 try { 553 done.acquire(); //done.P(); 554 } catch (InterruptedException e) { 555 throw new RuntimeException("interrupt in getNF"); 556 } 557 return H; 558 } 559 560 561 public void run() { 562 if (logger.isDebugEnabled()) { 563 logger.debug("ht(H) = " + H.leadingExpVector()); 564 } 565 try { 566 //H = red.normalform(G, H); //mod 567 H = redRec.normalformRecursive(G, H); 568 H = engine.recursivePrimitivePart(H); //H.monic(); 569 H = H.abs(); 570 done.release(); //done.V(); 571 } catch (RuntimeException e) { 572 Thread.currentThread().interrupt(); 573 //throw new RuntimeException("interrupt in getNF"); 574 } 575 if (logger.isDebugEnabled()) { 576 logger.debug("ht(H) = " + H.leadingExpVector()); 577 } 578 // H = H.monic(); 579 } 580 581}