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