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