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