001/* 002 * $Id: GroebnerBaseSeqPairParallel.java 5869 2018-07-20 15:53:10Z kredel $ 003 */ 004 005package edu.jas.gb; 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.poly.ExpVector; 018import edu.jas.poly.GenPolynomial; 019import edu.jas.structure.RingElem; 020import edu.jas.util.Terminator; 021import edu.jas.util.ThreadPool; 022 023 024/** 025 * Groebner Base parallel algorithm. Makes some effort to produce the same 026 * sequence of critical pairs as in the sequential version. However already 027 * reduced pairs are not rereduced if new polynomials appear. Implements a 028 * shared memory parallel version of Groebner bases. Slaves maintain pairlist. 029 * @param <C> coefficient type 030 * @author Heinz Kredel 031 */ 032 033public class GroebnerBaseSeqPairParallel<C extends RingElem<C>> extends GroebnerBaseAbstract<C> { 034 035 036 private static final Logger logger = LogManager.getLogger(GroebnerBaseSeqPairParallel.class); 037 038 039 /** 040 * Number of threads to use. 041 */ 042 protected final int threads; 043 044 045 /** 046 * Pool of threads to use. 047 */ 048 protected transient final ThreadPool pool; 049 050 051 /** 052 * Constructor. 053 */ 054 public GroebnerBaseSeqPairParallel() { 055 this(2); 056 } 057 058 059 /** 060 * Constructor. 061 * @param threads number of threads to use. 062 */ 063 public GroebnerBaseSeqPairParallel(int threads) { 064 this(threads, new ThreadPool(threads)); 065 } 066 067 068 /** 069 * Constructor. 070 * @param threads number of threads to use. 071 * @param pool ThreadPool to use. 072 */ 073 public GroebnerBaseSeqPairParallel(int threads, ThreadPool pool) { 074 this(threads, pool, new ReductionPar<C>()); 075 } 076 077 078 /** 079 * Constructor. 080 * @param threads number of threads to use. 081 * @param red parallelism aware reduction engine 082 */ 083 public GroebnerBaseSeqPairParallel(int threads, Reduction<C> red) { 084 this(threads, new ThreadPool(threads), red); 085 } 086 087 088 /** 089 * Constructor. 090 * @param threads number of threads to use. 091 * @param pool ThreadPool to use. 092 * @param red parallelism aware reduction engine 093 */ 094 public GroebnerBaseSeqPairParallel(int threads, ThreadPool pool, Reduction<C> red) { 095 super(red); 096 if (!(red instanceof ReductionPar)) { 097 logger.warn("parallel GB should use parallel aware reduction"); 098 } 099 if (threads < 1) { 100 threads = 1; 101 } 102 this.threads = threads; 103 this.pool = pool; 104 } 105 106 107 /** 108 * Cleanup and terminate ThreadPool. 109 */ 110 @Override 111 public void terminate() { 112 if (pool == null) { 113 return; 114 } 115 pool.terminate(); 116 } 117 118 119 /** 120 * Cancel ThreadPool. 121 */ 122 @Override 123 public int cancel() { 124 if (pool == null) { 125 return 0; 126 } 127 int s = pool.cancel(); 128 return s; 129 } 130 131 132 /** 133 * Parallel Groebner base using sequential pair order class. Slaves maintain 134 * pairlist. 135 * @param modv number of module variables. 136 * @param F polynomial list. 137 * @return GB(F) a Groebner base of F. 138 */ 139 public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) { 140 GenPolynomial<C> p; 141 List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>(); 142 CriticalPairList<C> pairlist = null; 143 int l = F.size(); 144 ListIterator<GenPolynomial<C>> it = F.listIterator(); 145 while (it.hasNext()) { 146 p = it.next(); 147 if (p.length() > 0) { 148 p = p.monic(); 149 if (p.isONE()) { 150 G.clear(); 151 G.add(p); 152 return G; // since no threads activated jet 153 } 154 G.add(p); 155 if (pairlist == null) { 156 pairlist = new CriticalPairList<C>(modv, p.ring); 157 if (!p.ring.coFac.isField()) { 158 throw new IllegalArgumentException("coefficients not from a field"); 159 } 160 } 161 // putOne not required 162 pairlist.put(p); 163 } else { 164 l--; 165 } 166 } 167 if (l <= 1) { 168 return G; // since no threads activated jet 169 } 170 171 Terminator fin = new Terminator(threads); 172 ReducerSeqPair<C> R; 173 for (int i = 0; i < threads; i++) { 174 R = new ReducerSeqPair<C>(fin, G, pairlist); 175 pool.addJob(R); 176 } 177 fin.waitDone(); 178 if (Thread.currentThread().isInterrupted()) { 179 throw new RuntimeException("interrupt before minimalGB"); 180 } 181 logger.debug("#parallel list = " + G.size()); 182 G = minimalGB(G); 183 // not in this context // pool.terminate(); 184 logger.info("" + pairlist); 185 return G; 186 } 187 188 189 /** 190 * Minimal ordered groebner basis, parallel. 191 * @param Fp a Groebner base. 192 * @return minimalGB(F) a minimal Groebner base of Fp. 193 */ 194 @Override 195 public List<GenPolynomial<C>> minimalGB(List<GenPolynomial<C>> Fp) { 196 GenPolynomial<C> a; 197 ArrayList<GenPolynomial<C>> G; 198 G = new ArrayList<GenPolynomial<C>>(Fp.size()); 199 ListIterator<GenPolynomial<C>> it = Fp.listIterator(); 200 while (it.hasNext()) { 201 a = it.next(); 202 if (a.length() != 0) { // always true 203 // already monic a = a.monic(); 204 G.add(a); 205 } 206 } 207 if (G.size() <= 1) { 208 return G; 209 } 210 211 ExpVector e; 212 ExpVector f; 213 GenPolynomial<C> p; 214 ArrayList<GenPolynomial<C>> F; 215 F = new ArrayList<GenPolynomial<C>>(G.size()); 216 boolean mt; 217 while (G.size() > 0) { 218 a = G.remove(0); 219 e = a.leadingExpVector(); 220 221 it = G.listIterator(); 222 mt = false; 223 while (it.hasNext() && !mt) { 224 p = it.next(); 225 f = p.leadingExpVector(); 226 mt = e.multipleOf(f); 227 } 228 it = F.listIterator(); 229 while (it.hasNext() && !mt) { 230 p = it.next(); 231 f = p.leadingExpVector(); 232 mt = e.multipleOf(f); 233 } 234 if (!mt) { 235 F.add(a); // no thread at this point 236 } else { 237 // System.out.println("dropped " + a.length()); 238 } 239 } 240 G = F; 241 if (G.size() <= 1) { 242 return G; 243 } 244 Collections.reverse(G); // important for lex GB 245 246 @SuppressWarnings("cast") 247 MiReducerSeqPair<C>[] mirs = (MiReducerSeqPair<C>[]) new MiReducerSeqPair[G.size()]; 248 int i = 0; 249 F = new ArrayList<GenPolynomial<C>>(G.size()); 250 while (G.size() > 0) { 251 a = G.remove(0); 252 // System.out.println("doing " + a.length()); 253 List<GenPolynomial<C>> R = new ArrayList<GenPolynomial<C>>(G.size() + F.size()); 254 R.addAll(G); 255 R.addAll(F); 256 mirs[i] = new MiReducerSeqPair<C>(R, a); 257 pool.addJob(mirs[i]); 258 i++; 259 F.add(a); 260 } 261 G = F; 262 F = new ArrayList<GenPolynomial<C>>(G.size()); 263 for (i = 0; i < mirs.length; i++) { 264 a = mirs[i].getNF(); 265 F.add(a); 266 } 267 return F; 268 } 269 270} 271 272 273/** 274 * Reducing worker threads. 275 */ 276class ReducerSeqPair<C extends RingElem<C>> implements Runnable { 277 278 279 private final List<GenPolynomial<C>> G; 280 281 282 private final CriticalPairList<C> pairlist; 283 284 285 private final Terminator fin; 286 287 288 private final ReductionPar<C> red; 289 290 291 private static final Logger logger = LogManager.getLogger(ReducerSeqPair.class); 292 293 294 ReducerSeqPair(Terminator fin, List<GenPolynomial<C>> G, CriticalPairList<C> L) { 295 this.fin = fin; 296 this.G = G; 297 pairlist = L; 298 red = new ReductionPar<C>(); 299 } 300 301 302 /** 303 * to string 304 */ 305 @Override 306 public String toString() { 307 return "ReducerSeqPair"; 308 } 309 310 311 public void run() { 312 CriticalPair<C> pair; 313 GenPolynomial<C> S; 314 GenPolynomial<C> H; 315 boolean set = false; 316 int reduction = 0; 317 int sleeps = 0; 318 while (pairlist.hasNext() || fin.hasJobs()) { 319 while (!pairlist.hasNext()) { 320 pairlist.update(); 321 // wait 322 fin.beIdle(); 323 set = true; 324 try { 325 sleeps++; 326 if (sleeps % 10 == 0) { 327 logger.info(" reducer is sleeping"); 328 } else { 329 logger.debug("r"); 330 } 331 Thread.sleep(100); 332 } catch (InterruptedException e) { 333 fin.allIdle(); 334 logger.info("shutdown " + fin + " after: " + e); 335 //throw new RuntimeException("interrupt 1 in pairlist.hasNext loop"); 336 break; 337 } 338 if (Thread.currentThread().isInterrupted()) { 339 fin.allIdle(); 340 logger.info("shutdown after .isInterrupted(): " + fin); 341 //throw new RuntimeException("interrupt 2 in pairlist.hasNext loop"); 342 break; 343 } 344 if (!fin.hasJobs()) { 345 break; 346 } 347 } 348 if (!pairlist.hasNext() && !fin.hasJobs()) { 349 break; 350 } 351 if (set) { 352 fin.notIdle(); 353 set = false; 354 } 355 pair = pairlist.getNext(); 356 if (Thread.currentThread().isInterrupted()) { 357 throw new RuntimeException("interrupt after getNext"); 358 } 359 if (pair == null) { 360 pairlist.update(); 361 continue; 362 } 363 if (logger.isDebugEnabled()) { 364 logger.debug("pi = " + pair.pi); 365 logger.debug("pj = " + pair.pj); 366 } 367 S = red.SPolynomial(pair.pi, pair.pj); 368 if (S.isZERO()) { 369 pairlist.record(pair, S); 370 continue; 371 } 372 if (logger.isDebugEnabled()) { 373 logger.debug("ht(S) = " + S.leadingExpVector()); 374 } 375 H = red.normalform(G, S); //mod 376 reduction++; 377 if (H.isZERO()) { 378 pairlist.record(pair, H); 379 continue; 380 } 381 if (logger.isDebugEnabled()) { 382 logger.debug("ht(H) = " + H.leadingExpVector()); 383 } 384 H = H.monic(); 385 // System.out.println("H = " + H); 386 if (H.isONE()) { 387 // pairlist.update( pair, H ); 388 pairlist.putOne(); // not really required 389 synchronized (G) { 390 G.clear(); 391 G.add(H); 392 } 393 fin.allIdle(); 394 return; 395 } 396 if (logger.isDebugEnabled()) { 397 logger.debug("H = " + H); 398 } 399 synchronized (G) { 400 G.add(H); 401 } 402 pairlist.update(pair, H); 403 //pairlist.record( pair, H ); 404 //pairlist.update(); 405 } 406 logger.info("terminated, done " + reduction + " reductions"); 407 } 408} 409 410 411/** 412 * Reducing worker threads for minimal GB. 413 */ 414class MiReducerSeqPair<C extends RingElem<C>> implements Runnable { 415 416 417 private final List<GenPolynomial<C>> G; 418 419 420 private GenPolynomial<C> H; 421 422 423 private final ReductionPar<C> red; 424 425 426 private final Semaphore done = new Semaphore(0); 427 428 429 private static final Logger logger = LogManager.getLogger(MiReducerSeqPair.class); 430 431 432 MiReducerSeqPair(List<GenPolynomial<C>> G, GenPolynomial<C> p) { 433 this.G = G; 434 H = p; 435 red = new ReductionPar<C>(); 436 } 437 438 439 /** 440 * to string 441 */ 442 @Override 443 public String toString() { 444 return "MiReducerSeqpair"; 445 } 446 447 448 /** 449 * getNF. Blocks until the normal form is computed. 450 * @return the computed normal form. 451 */ 452 public GenPolynomial<C> getNF() { 453 try { 454 done.acquire(); //done.P(); 455 } catch (InterruptedException e) { 456 throw new RuntimeException("interrupt in getNF"); 457 } 458 return H; 459 } 460 461 462 public void run() { 463 if (logger.isDebugEnabled()) { 464 logger.debug("ht(H) = " + H.leadingExpVector()); 465 } 466 try { 467 H = red.normalform(G, H); //mod 468 done.release(); //done.V(); 469 } catch (RuntimeException e) { 470 Thread.currentThread().interrupt(); 471 //throw new RuntimeException("interrupt in getNF"); 472 } 473 if (logger.isDebugEnabled()) { 474 logger.debug("ht(H) = " + H.leadingExpVector()); 475 } 476 // H = H.monic(); 477 } 478 479}