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