001/* 002 * $Id: SolvableGroebnerBaseParallel.java 5539 2016-07-24 14:51:48Z kredel $ 003 */ 004 005package edu.jas.gb; 006 007 008import java.util.ArrayList; 009import java.util.List; 010import java.util.ListIterator; 011import java.util.concurrent.Semaphore; 012 013import org.apache.log4j.Logger; 014 015import edu.jas.poly.ExpVector; 016import edu.jas.poly.GenSolvablePolynomial; 017import edu.jas.poly.GenSolvablePolynomialRing; 018import edu.jas.poly.PolynomialList; 019import edu.jas.poly.PolyUtil; 020import edu.jas.structure.RingElem; 021import edu.jas.util.Terminator; 022import edu.jas.util.ThreadPool; 023 024 025/** 026 * Solvable Groebner Base parallel algorithm. Implements a shared memory 027 * parallel version of Groebner bases. Threads maintain pairlist. 028 * @param <C> coefficient type 029 * @author Heinz Kredel 030 */ 031 032public class SolvableGroebnerBaseParallel<C extends RingElem<C>> extends SolvableGroebnerBaseAbstract<C> { 033 034 035 private static final Logger logger = Logger.getLogger(SolvableGroebnerBaseParallel.class); 036 037 038 //private static final boolean debug = logger.isDebugEnabled(); 039 040 041 /** 042 * Number of threads to use. 043 */ 044 protected final int threads; 045 046 047 /** 048 * Pool of threads to use. 049 */ 050 protected transient final ThreadPool pool; 051 052 053 /** 054 * Constructor. 055 */ 056 public SolvableGroebnerBaseParallel() { 057 this(2); 058 } 059 060 061 /** 062 * Constructor. 063 * @param threads number of threads to use. 064 */ 065 public SolvableGroebnerBaseParallel(int threads) { 066 this(threads, new ThreadPool(threads)); 067 } 068 069 070 /** 071 * Constructor. 072 * @param threads number of threads to use. 073 * @param pool ThreadPool to use. 074 */ 075 public SolvableGroebnerBaseParallel(int threads, ThreadPool pool) { 076 this(threads, pool, new SolvableReductionPar<C>()); 077 } 078 079 080 /** 081 * Constructor. 082 * @param threads number of threads to use. 083 * @param sred parallelism aware reduction engine 084 */ 085 public SolvableGroebnerBaseParallel(int threads, SolvableReduction<C> sred) { 086 this(threads, new ThreadPool(threads), sred); 087 } 088 089 090 /** 091 * Constructor. 092 * @param threads number of threads to use. 093 * @param pl pair selection strategy 094 */ 095 public SolvableGroebnerBaseParallel(int threads, PairList<C> pl) { 096 this(threads, new ThreadPool(threads), new SolvableReductionPar<C>(), pl); 097 } 098 099 100 /** 101 * Constructor. 102 * @param threads number of threads to use. 103 * @param sred parallelism aware reduction engine 104 * @param pl pair selection strategy 105 */ 106 public SolvableGroebnerBaseParallel(int threads, SolvableReduction<C> sred, PairList<C> pl) { 107 this(threads, new ThreadPool(threads), sred, pl); 108 } 109 110 111 /** 112 * Constructor. 113 * @param threads number of threads to use. 114 * @param pool ThreadPool to use. 115 * @param sred parallelism aware reduction engine 116 */ 117 public SolvableGroebnerBaseParallel(int threads, ThreadPool pool, SolvableReduction<C> sred) { 118 this(threads, pool, sred, new OrderedPairlist<C>()); 119 } 120 121 122 /** 123 * Constructor. 124 * @param threads number of threads to use. 125 * @param pool ThreadPool to use. 126 * @param sred parallelism aware reduction engine 127 * @param pl pair selection strategy 128 */ 129 public SolvableGroebnerBaseParallel(int threads, ThreadPool pool, SolvableReduction<C> sred, 130 PairList<C> pl) { 131 super(sred, pl); 132 if (!(sred instanceof SolvableReductionPar)) { 133 logger.warn("parallel GB should use parallel aware reduction"); 134 } 135 if (threads < 1) { 136 threads = 1; 137 } 138 this.threads = threads; 139 this.pool = pool; 140 } 141 142 143 /** 144 * Cleanup and terminate ThreadPool. 145 */ 146 @Override 147 public void terminate() { 148 if (pool == null) { 149 return; 150 } 151 pool.terminate(); 152 } 153 154 155 /** 156 * Parallel Groebner base using sequential pair order class. Threads 157 * maintain pairlist. 158 * @param modv number of module variables. 159 * @param F polynomial list. 160 * @return GB(F) a Groebner base of F. 161 */ 162 public List<GenSolvablePolynomial<C>> leftGB(int modv, List<GenSolvablePolynomial<C>> F) { 163 List<GenSolvablePolynomial<C>> G = normalizeZerosOnes(F); 164 G = PolynomialList.castToSolvableList(PolyUtil.<C> monic(PolynomialList.castToList(G))); 165 if (G.size() <= 1) { 166 return G; 167 } 168 GenSolvablePolynomialRing<C> ring = G.get(0).ring; 169 if (!ring.coFac.isField() && ring.coFac.isCommutative()) { 170 throw new IllegalArgumentException("coefficients not from a field"); 171 } 172 PairList<C> pairlist = strategy.create(modv, ring); 173 pairlist.put(PolynomialList.castToList(G)); 174 logger.info("start " + pairlist); 175 176 Terminator fin = new Terminator(threads); 177 LeftSolvableReducer<C> R; 178 for (int i = 0; i < threads; i++) { 179 R = new LeftSolvableReducer<C>(fin, G, pairlist); 180 pool.addJob(R); 181 } 182 fin.waitDone(); 183 logger.debug("#parallel list = " + G.size()); 184 G = leftMinimalGB(G); 185 // not in this context // pool.terminate(); 186 logger.info("end " + pairlist); 187 return G; 188 } 189 190 191 /** 192 * Minimal ordered groebner basis, parallel. 193 * @param Fp a Groebner base. 194 * @return minimalGB(F) a minimal Groebner base of Fp. 195 */ 196 @Override 197 public List<GenSolvablePolynomial<C>> leftMinimalGB(List<GenSolvablePolynomial<C>> Fp) { 198 GenSolvablePolynomial<C> a; 199 ArrayList<GenSolvablePolynomial<C>> G; 200 G = new ArrayList<GenSolvablePolynomial<C>>(Fp.size()); 201 ListIterator<GenSolvablePolynomial<C>> it = Fp.listIterator(); 202 while (it.hasNext()) { 203 a = it.next(); 204 if (a.length() != 0) { // always true 205 // already monic a = a.monic(); 206 G.add(a); 207 } 208 } 209 if (G.size() <= 1) { 210 return G; 211 } 212 213 ExpVector e; 214 ExpVector f; 215 GenSolvablePolynomial<C> p; 216 ArrayList<GenSolvablePolynomial<C>> F; 217 F = new ArrayList<GenSolvablePolynomial<C>>(G.size()); 218 boolean mt; 219 while (G.size() > 0) { 220 a = G.remove(0); 221 e = a.leadingExpVector(); 222 223 it = G.listIterator(); 224 mt = false; 225 while (it.hasNext() && !mt) { 226 p = it.next(); 227 f = p.leadingExpVector(); 228 mt = e.multipleOf(f); 229 } 230 it = F.listIterator(); 231 while (it.hasNext() && !mt) { 232 p = it.next(); 233 f = p.leadingExpVector(); 234 mt = e.multipleOf(f); 235 } 236 if (!mt) { 237 F.add(a); // no thread at this point 238 } else { 239 // System.out.println("dropped " + a.length()); 240 } 241 } 242 G = F; 243 if (G.size() <= 1) { 244 return G; 245 } 246 247 @SuppressWarnings("cast") 248 SolvableMiReducer<C>[] mirs = (SolvableMiReducer<C>[]) new SolvableMiReducer[G.size()]; 249 int i = 0; 250 F = new ArrayList<GenSolvablePolynomial<C>>(G.size()); 251 while (G.size() > 0) { 252 a = G.remove(0); 253 // System.out.println("doing " + a.length()); 254 List<GenSolvablePolynomial<C>> R = new ArrayList<GenSolvablePolynomial<C>>(G.size() + F.size()); 255 R.addAll(G); 256 R.addAll(F); 257 mirs[i] = new SolvableMiReducer<C>(R, a); 258 pool.addJob(mirs[i]); 259 i++; 260 F.add(a); 261 } 262 G = F; 263 F = new ArrayList<GenSolvablePolynomial<C>>(G.size()); 264 for (i = 0; i < mirs.length; i++) { 265 a = mirs[i].getNF(); 266 F.add(a); 267 } 268 return F; 269 } 270 271 272 /** 273 * Solvable Extended Groebner base using critical pair class. 274 * @param modv module variable number. 275 * @param F solvable polynomial list. 276 * @return a container for an extended left Groebner base of F. 277 */ 278 @Override 279 public SolvableExtendedGB<C> extLeftGB(int modv, List<GenSolvablePolynomial<C>> F) { 280 throw new UnsupportedOperationException("parallel extLeftGB not implemented"); 281 } 282 283 284 /** 285 * Twosided Groebner base using pairlist class. 286 * @param modv number of module variables. 287 * @param Fp solvable polynomial list. 288 * @return tsGB(Fp) a twosided Groebner base of F. 289 */ 290 @SuppressWarnings("unchecked") 291 public List<GenSolvablePolynomial<C>> twosidedGB(int modv, List<GenSolvablePolynomial<C>> Fp) { 292 List<GenSolvablePolynomial<C>> G = normalizeZerosOnes(Fp); 293 G = PolynomialList.castToSolvableList(PolyUtil.<C> monic(PolynomialList.castToList(G))); 294 if (G.size() < 1) { // 0 not 1 295 return G; 296 } 297 if (G.size() <= 1) { 298 if (G.get(0).isONE()) { 299 return G; 300 } 301 } 302 GenSolvablePolynomialRing<C> ring = G.get(0).ring; 303 if (!ring.coFac.isField() && ring.coFac.isCommutative()) { 304 throw new IllegalArgumentException("coefficients not from a field"); 305 } 306 // add also coefficient generators 307 List<GenSolvablePolynomial<C>> X; 308 X = PolynomialList.castToSolvableList(ring.generators(modv)); 309 logger.info("right multipliers = " + X); 310 List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(G.size() * (1 + X.size())); 311 F.addAll(G); 312 GenSolvablePolynomial<C> p, x, q; 313 for (int i = 0; i < F.size(); i++) { // F changes 314 p = F.get(i); 315 for (int j = 0; j < X.size(); j++) { 316 x = X.get(j); 317 if (x.isONE()) { 318 continue; 319 } 320 q = p.multiply(x); 321 q = sred.leftNormalform(F, q); 322 if (!q.isZERO()) { 323 q = q.monic(); 324 if (q.isONE()) { 325 G.clear(); 326 G.add(q); 327 return G; 328 } 329 F.add(q); 330 } 331 } 332 } 333 //System.out.println("F generated = " + F); 334 G = F; 335 if (G.size() <= 1) { // 1 okay here 336 return G; 337 } 338 PairList<C> pairlist = strategy.create(modv, ring); 339 pairlist.put(PolynomialList.castToList(G)); 340 logger.info("start " + pairlist); 341 342 Terminator fin = new Terminator(threads); 343 TwosidedSolvableReducer<C> R; 344 for (int i = 0; i < threads; i++) { 345 R = new TwosidedSolvableReducer<C>(fin, modv, X, G, pairlist); 346 pool.addJob(R); 347 } 348 fin.waitDone(); 349 logger.debug("#parallel list = " + G.size()); 350 G = leftMinimalGB(G); 351 // not in this context // pool.terminate(); 352 logger.info("end " + pairlist); 353 return G; 354 } 355 356} 357 358 359/** 360 * Reducing left worker threads. 361 * @param <C> coefficient type 362 */ 363class LeftSolvableReducer<C extends RingElem<C>> implements Runnable { 364 365 366 private final List<GenSolvablePolynomial<C>> G; 367 368 369 private final PairList<C> pairlist; 370 371 372 private final Terminator pool; 373 374 375 private final SolvableReductionPar<C> sred; 376 377 378 private static final Logger logger = Logger.getLogger(LeftSolvableReducer.class); 379 380 381 private static final boolean debug = logger.isDebugEnabled(); 382 383 384 LeftSolvableReducer(Terminator fin, List<GenSolvablePolynomial<C>> G, PairList<C> L) { 385 pool = fin; 386 this.G = G; 387 pairlist = L; 388 sred = new SolvableReductionPar<C>(); 389 } 390 391 392 @SuppressWarnings("unchecked") 393 public void run() { 394 Pair<C> pair; 395 GenSolvablePolynomial<C> S; 396 GenSolvablePolynomial<C> H; 397 boolean set = false; 398 int reduction = 0; 399 int sleeps = 0; 400 while (pairlist.hasNext() || pool.hasJobs()) { 401 while (!pairlist.hasNext()) { 402 // wait 403 pool.beIdle(); 404 set = true; 405 try { 406 sleeps++; 407 if (sleeps % 10 == 0) { 408 logger.info(" reducer is sleeping"); 409 } else { 410 logger.debug("r"); 411 } 412 Thread.sleep(100); 413 } catch (InterruptedException e) { 414 pool.allIdle(); 415 logger.info("shutdown " + pool + " after: " + e); 416 //throw new RuntimeException("interrupt 1 in pairlist.hasNext loop"); 417 break; 418 } 419 if (Thread.currentThread().isInterrupted()) { 420 //pool.initIdle(1); 421 pool.allIdle(); 422 logger.info("shutdown after .isInterrupted(): " + pool); 423 //throw new RuntimeException("interrupt 2 in pairlist.hasNext loop"); 424 break; 425 } 426 if (!pool.hasJobs()) { 427 break; 428 } 429 } 430 if (!pairlist.hasNext() && !pool.hasJobs()) { 431 break; 432 } 433 if (set) { 434 pool.notIdle(); 435 set = false; 436 } 437 pair = pairlist.removeNext(); 438 if (pair == null) { 439 continue; 440 } 441 if (debug) { 442 logger.debug("pi = " + pair.pi); 443 logger.debug("pj = " + pair.pj); 444 } 445 S = sred.leftSPolynomial((GenSolvablePolynomial<C>) pair.pi, (GenSolvablePolynomial<C>) pair.pj); 446 if (S.isZERO()) { 447 continue; 448 } 449 if (debug) { 450 logger.debug("ht(S) = " + S.leadingExpVector()); 451 } 452 H = sred.leftNormalform(G, S); //mod 453 reduction++; 454 if (H.isZERO()) { 455 continue; 456 } 457 if (debug) { 458 logger.debug("ht(H) = " + H.leadingExpVector()); 459 } 460 H = H.monic(); 461 // System.out.println("H = " + H); 462 if (H.isONE()) { 463 pairlist.putOne(); // not really required 464 synchronized (G) { 465 G.clear(); 466 G.add(H); 467 } 468 pool.allIdle(); 469 return; 470 } 471 if (debug) { 472 logger.debug("H = " + H); 473 } 474 synchronized (G) { 475 G.add(H); 476 } 477 pairlist.put(H); 478 } 479 logger.info("terminated, done " + reduction + " reductions"); 480 } 481} 482 483 484/** 485 * Reducing twosided worker threads. 486 * @param <C> coefficient type 487 */ 488class TwosidedSolvableReducer<C extends RingElem<C>> implements Runnable { 489 490 491 private final List<GenSolvablePolynomial<C>> X; 492 493 494 private final List<GenSolvablePolynomial<C>> G; 495 496 497 private final PairList<C> pairlist; 498 499 500 private final int modv; 501 502 503 private final Terminator pool; 504 505 506 private final SolvableReductionPar<C> sred; 507 508 509 private static final Logger logger = Logger.getLogger(TwosidedSolvableReducer.class); 510 511 512 private static final boolean debug = logger.isDebugEnabled(); 513 514 515 TwosidedSolvableReducer(Terminator fin, int modv, List<GenSolvablePolynomial<C>> X, 516 List<GenSolvablePolynomial<C>> G, PairList<C> L) { 517 pool = fin; 518 this.modv = modv; 519 this.X = X; 520 this.G = G; 521 pairlist = L; 522 sred = new SolvableReductionPar<C>(); 523 } 524 525 526 public void run() { 527 GenSolvablePolynomial<C> p, x, S, H; 528 Pair<C> pair; 529 boolean set = false; 530 int reduction = 0; 531 int sleeps = 0; 532 logger.debug("modv = " + modv); // avoid "unused" 533 while (pairlist.hasNext() || pool.hasJobs()) { 534 while (!pairlist.hasNext()) { 535 // wait 536 pool.beIdle(); 537 set = true; 538 try { 539 sleeps++; 540 if (sleeps % 10 == 0) { 541 logger.info(" reducer is sleeping"); 542 } else { 543 logger.debug("r"); 544 } 545 Thread.sleep(50); 546 } catch (InterruptedException e) { 547 break; 548 } 549 if (!pool.hasJobs()) { 550 break; 551 } 552 } 553 if (!pairlist.hasNext() && !pool.hasJobs()) { 554 break; 555 } 556 if (set) { 557 pool.notIdle(); 558 set = false; 559 } 560 pair = pairlist.removeNext(); 561 if (pair == null) { 562 continue; 563 } 564 if (debug) { 565 logger.debug("pi = " + pair.pi); 566 logger.debug("pj = " + pair.pj); 567 } 568 S = sred.leftSPolynomial((GenSolvablePolynomial<C>) pair.pi, (GenSolvablePolynomial<C>) pair.pj); 569 if (S.isZERO()) { 570 continue; 571 } 572 if (debug) { 573 logger.debug("ht(S) = " + S.leadingExpVector()); 574 } 575 H = sred.leftNormalform(G, S); //mod 576 reduction++; 577 if (H.isZERO()) { 578 continue; 579 } 580 if (debug) { 581 logger.debug("ht(H) = " + H.leadingExpVector()); 582 } 583 H = H.monic(); 584 // System.out.println("H = " + H); 585 if (H.isONE()) { 586 pairlist.putOne(); // not really required 587 synchronized (G) { 588 G.clear(); 589 G.add(H); 590 } 591 pool.allIdle(); 592 return; 593 } 594 if (debug) { 595 logger.debug("H = " + H); 596 } 597 synchronized (G) { 598 G.add(H); 599 } 600 pairlist.put(H); 601 for (int j = 0; j < X.size(); j++) { 602 x = X.get(j); 603 p = H.multiply(x); 604 p = sred.leftNormalform(G, p); 605 if (!p.isZERO()) { 606 p = p.monic(); 607 if (p.isONE()) { 608 synchronized (G) { 609 G.clear(); 610 G.add(p); 611 } 612 pool.allIdle(); 613 return; 614 } 615 synchronized (G) { 616 G.add(p); 617 } 618 pairlist.put(p); 619 } 620 } 621 } 622 logger.info("terminated, done " + reduction + " reductions"); 623 } 624} 625 626 627/** 628 * Reducing worker threads for minimal GB. 629 * @param <C> coefficient type 630 */ 631class SolvableMiReducer<C extends RingElem<C>> implements Runnable { 632 633 634 private final List<GenSolvablePolynomial<C>> G; 635 636 637 private GenSolvablePolynomial<C> H; 638 639 640 private final SolvableReductionPar<C> sred; 641 642 643 private final Semaphore done = new Semaphore(0); 644 645 646 private static final Logger logger = Logger.getLogger(SolvableMiReducer.class); 647 648 649 private static final boolean debug = logger.isDebugEnabled(); 650 651 652 SolvableMiReducer(List<GenSolvablePolynomial<C>> G, GenSolvablePolynomial<C> p) { 653 this.G = G; 654 H = p; 655 sred = new SolvableReductionPar<C>(); 656 } 657 658 659 /** 660 * getNF. Blocks until the normal form is computed. 661 * @return the computed normal form. 662 */ 663 public GenSolvablePolynomial<C> getNF() { 664 try { 665 done.acquire(); //done.P(); 666 } catch (InterruptedException e) { 667 } 668 return H; 669 } 670 671 672 public void run() { 673 if (debug) { 674 logger.debug("ht(H) = " + H.leadingExpVector()); 675 } 676 H = sred.leftNormalform(G, H); //mod 677 done.release(); //done.V(); 678 if (debug) { 679 logger.debug("ht(H) = " + H.leadingExpVector()); 680 } 681 // H = H.monic(); 682 } 683 684}