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