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