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