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