001/* 002 * $Id: GroebnerBasePseudoRecParallel.java 5061 2015-01-01 19:45:33Z kredel $ 003 */ 004 005package edu.jas.gbufd; 006 007 008import java.util.ArrayList; 009import java.util.Collections; 010import java.util.List; 011import java.util.concurrent.Semaphore; 012 013import org.apache.log4j.Logger; 014 015import edu.jas.gb.GroebnerBaseAbstract; 016import edu.jas.gb.OrderedPairlist; 017import edu.jas.gb.Pair; 018import edu.jas.gb.PairList; 019import edu.jas.poly.ExpVector; 020import edu.jas.poly.GenPolynomial; 021import edu.jas.poly.GenPolynomialRing; 022import edu.jas.structure.GcdRingElem; 023import edu.jas.structure.RingFactory; 024import edu.jas.ufd.GCDFactory; 025import edu.jas.ufd.GreatestCommonDivisorAbstract; 026import edu.jas.util.Terminator; 027import edu.jas.util.ThreadPool; 028 029 030/** 031 * Groebner Base with recursive pseudo reduction multi-threaded parallel 032 * algorithm. Implements coefficient fraction free Groebner bases. 033 * Coefficients can for example be (commutative) multivariate polynomials. 034 * @param <C> coefficient type 035 * @author Heinz Kredel 036 * 037 * @see edu.jas.application.GBAlgorithmBuilder 038 * @see edu.jas.gbufd.GBFactory 039 */ 040 041public class GroebnerBasePseudoRecParallel<C extends GcdRingElem<C>> extends 042 GroebnerBaseAbstract<GenPolynomial<C>> { 043 044 045 private static final Logger logger = Logger.getLogger(GroebnerBasePseudoRecParallel.class); 046 047 048 private final boolean debug = logger.isDebugEnabled(); 049 050 051 /** 052 * Number of threads to use. 053 */ 054 protected final int threads; 055 056 057 /** 058 * Pool of threads to use. 059 */ 060 protected transient final ThreadPool pool; 061 062 063 /** 064 * Greatest common divisor engine for coefficient content and primitive 065 * parts. 066 */ 067 protected final GreatestCommonDivisorAbstract<C> engine; 068 069 070 /** 071 * Pseudo reduction engine. 072 */ 073 protected final PseudoReduction<C> redRec; 074 075 076 /** 077 * Pseudo reduction engine. 078 */ 079 protected final PseudoReduction<GenPolynomial<C>> red; 080 081 082 /** 083 * Coefficient ring factory. 084 */ 085 protected final RingFactory<GenPolynomial<C>> cofac; 086 087 088 /** 089 * Base coefficient ring factory. 090 */ 091 protected final RingFactory<C> baseCofac; 092 093 094 /** 095 * Constructor. 096 * @param threads number of threads to use. 097 * @param rf coefficient ring factory. 098 */ 099 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf) { 100 this(threads, rf, new PseudoReductionPar<GenPolynomial<C>>(), new ThreadPool(threads), 101 new OrderedPairlist<GenPolynomial<C>>(new GenPolynomialRing<GenPolynomial<C>>(rf, 1))); // 1=hack 102 } 103 104 105 /** 106 * Constructor. 107 * @param threads number of threads to use. 108 * @param rf coefficient ring factory. <b>Note:</b> red must be an instance 109 * of PseudoReductionPar. 110 * @param red pseudo reduction engine. 111 */ 112 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf, 113 PseudoReduction<GenPolynomial<C>> red) { 114 this(threads, rf, red, new ThreadPool(threads)); 115 } 116 117 118 /** 119 * Constructor. 120 * @param threads number of threads to use. 121 * @param rf coefficient ring factory. <b>Note:</b> red must be an instance 122 * of PseudoReductionPar. 123 * @param red pseudo reduction engine. 124 * @param pool ThreadPool to use. 125 */ 126 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf, 127 PseudoReduction<GenPolynomial<C>> red, ThreadPool pool) { 128 this(threads, rf, red, pool, new OrderedPairlist<GenPolynomial<C>>( 129 new GenPolynomialRing<GenPolynomial<C>>(rf, 1))); // 1=hack 130 } 131 132 133 /** 134 * Constructor. 135 * @param threads number of threads to use. 136 * @param rf coefficient ring factory. <b>Note:</b> red must be an instance 137 * of PseudoReductionPar. 138 * @param pl pair selection strategy 139 */ 140 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf, 141 PairList<GenPolynomial<C>> pl) { 142 this(threads, rf, new PseudoReductionPar<GenPolynomial<C>>(), new ThreadPool(threads), pl); 143 } 144 145 146 /** 147 * Constructor. 148 * @param threads number of threads to use. 149 * @param rf coefficient ring factory. <b>Note:</b> red must be an instance 150 * of PseudoReductionPar. 151 * @param red pseudo reduction engine. 152 * @param pool ThreadPool to use. 153 * @param pl pair selection strategy 154 */ 155 @SuppressWarnings("cast") 156 public GroebnerBasePseudoRecParallel(int threads, RingFactory<GenPolynomial<C>> rf, 157 PseudoReduction<GenPolynomial<C>> red, ThreadPool pool, PairList<GenPolynomial<C>> pl) { 158 super(red, pl); 159 if (!(red instanceof PseudoReductionPar)) { 160 logger.warn("parallel GB should use parallel aware reduction"); 161 } 162 this.red = red; 163 this.redRec = (PseudoReduction<C>) (PseudoReduction) red; 164 cofac = rf; 165 if (threads < 1) { 166 threads = 1; 167 } 168 this.threads = threads; 169 GenPolynomialRing<C> rp = (GenPolynomialRing<C>) cofac; 170 baseCofac = rp.coFac; 171 //engine = (GreatestCommonDivisorAbstract<C>)GCDFactory.<C>getImplementation( baseCofac ); 172 //not used: 173 engine = GCDFactory.<C> getProxy(baseCofac); 174 this.pool = pool; 175 } 176 177 178 /** 179 * Cleanup and terminate ThreadPool. 180 */ 181 @Override 182 public void terminate() { 183 if (pool == null) { 184 return; 185 } 186 pool.terminate(); 187 } 188 189 190 /** 191 * Cancel ThreadPool. 192 */ 193 @Override 194 public int cancel() { 195 if (pool == null) { 196 return 0; 197 } 198 int s = pool.cancel(); 199 return s; 200 } 201 202 203 /** 204 * Groebner base using pairlist class. 205 * @param modv module variable number. 206 * @param F polynomial list. 207 * @return GB(F) a Groebner base of F. 208 */ 209 public List<GenPolynomial<GenPolynomial<C>>> GB(int modv, List<GenPolynomial<GenPolynomial<C>>> F) { 210 List<GenPolynomial<GenPolynomial<C>>> G = normalizeZerosOnes(F); 211 G = engine.recursivePrimitivePart(G); 212 if (G.size() <= 1) { 213 return G; 214 } 215 GenPolynomialRing<GenPolynomial<C>> ring = G.get(0).ring; 216 if (ring.coFac.isField()) { // TODO remove 217 throw new IllegalArgumentException("coefficients from a field"); 218 } 219 PairList<GenPolynomial<C>> pairlist = strategy.create(modv, ring); 220 pairlist.put(G); 221 222 /* 223 GenPolynomial<GenPolynomial<C>> p; 224 List<GenPolynomial<GenPolynomial<C>>> G = new ArrayList<GenPolynomial<GenPolynomial<C>>>(); 225 PairList<GenPolynomial<C>> pairlist = null; 226 int l = F.size(); 227 ListIterator<GenPolynomial<GenPolynomial<C>>> it = F.listIterator(); 228 while (it.hasNext()) { 229 p = it.next(); 230 if (p.length() > 0) { 231 p = engine.recursivePrimitivePart(p); //p.monic(); 232 p = p.abs(); 233 if (p.isConstant()) { 234 G.clear(); 235 G.add(p); 236 return G; // since no threads are activated 237 } 238 G.add(p); 239 if (pairlist == null) { 240 //pairlist = new OrderedPairlist<C>(modv, p.ring); 241 pairlist = strategy.create(modv, p.ring); 242 } 243 // putOne not required 244 pairlist.put(p); 245 } else { 246 l--; 247 } 248 } 249 if (l <= 1) { 250 return G; // since no threads are activated 251 } 252 */ 253 logger.info("start " + pairlist); 254 255 Terminator fin = new Terminator(threads); 256 PseudoReducerRec<C> R; 257 for (int i = 0; i < threads; i++) { 258 R = new PseudoReducerRec<C>(fin, G, pairlist, engine); 259 pool.addJob(R); 260 } 261 fin.waitDone(); 262 if (Thread.currentThread().isInterrupted()) { 263 throw new RuntimeException("interrupt before minimalGB"); 264 } 265 logger.debug("#parallel list = " + G.size()); 266 G = minimalGB(G); 267 logger.info("" + pairlist); 268 return G; 269 } 270 271 272 /** 273 * Minimal ordered Groebner basis. 274 * @param Gp a Groebner base. 275 * @return a reduced Groebner base of Gp. 276 */ 277 @Override 278 public List<GenPolynomial<GenPolynomial<C>>> minimalGB(List<GenPolynomial<GenPolynomial<C>>> Gp) { 279 List<GenPolynomial<GenPolynomial<C>>> G = normalizeZerosOnes(Gp); 280 /* 281 if (Gp == null || Gp.size() <= 1) { 282 return Gp; 283 } 284 // remove zero polynomials 285 List<GenPolynomial<GenPolynomial<C>>> G = new ArrayList<GenPolynomial<GenPolynomial<C>>>(Gp.size()); 286 for (GenPolynomial<GenPolynomial<C>> a : Gp) { 287 if (a != null && !a.isZERO()) { // always true in GB() 288 // already positive a = a.abs(); 289 G.add(a); 290 } 291 } 292 */ 293 if (G.size() <= 1) { 294 return G; 295 } 296 // remove top reducible polynomials 297 GenPolynomial<GenPolynomial<C>> a; 298 List<GenPolynomial<GenPolynomial<C>>> F; 299 F = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size()); 300 while (G.size() > 0) { 301 a = G.remove(0); 302 if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { 303 // drop polynomial 304 if (debug) { 305 System.out.println("dropped " + a); 306 List<GenPolynomial<GenPolynomial<C>>> ff; 307 ff = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G); 308 ff.addAll(F); 309 //a = red.normalform(ff, a); 310 a = redRec.normalformRecursive(ff, a); 311 if (!a.isZERO()) { 312 System.out.println("error, nf(a) " + a); 313 } 314 } 315 } else { 316 F.add(a); 317 } 318 } 319 G = F; 320 if (G.size() <= 1) { 321 return G; 322 } 323 Collections.reverse(G); // important for lex GB 324 // reduce remaining polynomials 325 @SuppressWarnings("cast") 326 PseudoMiReducerRec<C>[] mirs = (PseudoMiReducerRec<C>[]) new PseudoMiReducerRec[G.size()]; 327 int i = 0; 328 F = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size()); 329 while (G.size() > 0) { 330 a = G.remove(0); 331 List<GenPolynomial<GenPolynomial<C>>> R = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size() 332 + F.size()); 333 R.addAll(G); 334 R.addAll(F); 335 // System.out.println("doing " + a.length()); 336 mirs[i] = new PseudoMiReducerRec<C>(R, a, engine); 337 pool.addJob(mirs[i]); 338 i++; 339 F.add(a); 340 } 341 G = F; 342 F = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size()); 343 for (i = 0; i < mirs.length; i++) { 344 a = mirs[i].getNF(); 345 F.add(a); 346 } 347 return F; 348 } 349 350 351 /** 352 * Groebner base simple test. 353 * @param modv module variable number. 354 * @param F recursive polynomial list. 355 * @return true, if F is a Groebner base, else false. 356 */ 357 @Override 358 public boolean isGBsimple(int modv, List<GenPolynomial<GenPolynomial<C>>> F) { 359 if (F == null || F.isEmpty()) { 360 return true; 361 } 362 GenPolynomial<GenPolynomial<C>> pi, pj, s, h; 363 ExpVector ei, ej, eij; 364 for (int i = 0; i < F.size(); i++) { 365 pi = F.get(i); 366 ei = pi.leadingExpVector(); 367 for (int j = i + 1; j < F.size(); j++) { 368 pj = F.get(j); 369 ej = pj.leadingExpVector(); 370 if (!red.moduleCriterion(modv, ei, ej)) { 371 continue; 372 } 373 eij = ei.lcm(ej); 374 if (!red.criterion4(ei, ej, eij)) { 375 continue; 376 } 377 //if (!criterion3(i, j, eij, F)) { 378 // continue; 379 //} 380 s = red.SPolynomial(pi, pj); 381 if (s.isZERO()) { 382 continue; 383 } 384 //System.out.println("i, j = " + i + ", " + j); 385 h = redRec.normalformRecursive(F, s); 386 if (!h.isZERO()) { 387 logger.info("no GB: pi = " + pi + ", pj = " + pj); 388 logger.info("s = " + s + ", h = " + h); 389 return false; 390 } 391 } 392 } 393 return true; 394 } 395 396} 397 398 399/** 400 * Pseudo GB Reducing worker threads. 401 */ 402class PseudoReducerRec<C extends GcdRingElem<C>> implements Runnable { 403 404 405 private final List<GenPolynomial<GenPolynomial<C>>> G; 406 407 408 private final PairList<GenPolynomial<C>> pairlist; 409 410 411 private final Terminator fin; 412 413 414 private final PseudoReductionPar<GenPolynomial<C>> red; 415 416 417 private final PseudoReductionPar<C> redRec; 418 419 420 private final GreatestCommonDivisorAbstract<C> engine; 421 422 423 private static final Logger logger = Logger.getLogger(PseudoReducerRec.class); 424 425 426 PseudoReducerRec(Terminator fin, List<GenPolynomial<GenPolynomial<C>>> G, PairList<GenPolynomial<C>> L, 427 GreatestCommonDivisorAbstract<C> engine) { 428 this.fin = fin; 429 this.G = G; 430 pairlist = L; 431 red = new PseudoReductionPar<GenPolynomial<C>>(); 432 redRec = new PseudoReductionPar<C>(); 433 this.engine = engine; 434 fin.initIdle(1); 435 } 436 437 438 /** 439 * to string 440 */ 441 @Override 442 public String toString() { 443 return "PseudoReducer"; 444 } 445 446 447 public void run() { 448 Pair<GenPolynomial<C>> pair; 449 GenPolynomial<GenPolynomial<C>> pi, pj, S, H; 450 //boolean set = false; 451 int reduction = 0; 452 int sleeps = 0; 453 while (pairlist.hasNext() || fin.hasJobs()) { 454 while (!pairlist.hasNext()) { 455 // wait 456 //fin.beIdle(); set = true; 457 try { 458 sleeps++; 459 if (sleeps % 10 == 0) { 460 logger.info(" reducer is sleeping"); 461 } else { 462 logger.debug("r"); 463 } 464 Thread.sleep(100); 465 } catch (InterruptedException e) { 466 break; 467 } 468 if (!fin.hasJobs()) { 469 break; 470 } 471 } 472 if (!pairlist.hasNext() && !fin.hasJobs()) { 473 break; 474 } 475 476 fin.notIdle(); // before pairlist get 477 pair = pairlist.removeNext(); 478 if (Thread.currentThread().isInterrupted()) { 479 fin.initIdle(1); 480 throw new RuntimeException("interrupt after removeNext"); 481 } 482 if (pair == null) { 483 fin.initIdle(1); 484 continue; 485 } 486 487 pi = pair.pi; 488 pj = pair.pj; 489 if (logger.isDebugEnabled()) { 490 logger.debug("pi = " + pi); 491 logger.debug("pj = " + pj); 492 } 493 494 S = red.SPolynomial(pi, pj); 495 if (S.isZERO()) { 496 pair.setZero(); 497 fin.initIdle(1); 498 continue; 499 } 500 if (logger.isDebugEnabled()) { 501 logger.debug("ht(S) = " + S.leadingExpVector()); 502 } 503 504 //H = red.normalform(G, S); //mod 505 H = redRec.normalformRecursive(G, S); 506 reduction++; 507 if (H.isZERO()) { 508 pair.setZero(); 509 fin.initIdle(1); 510 continue; 511 } 512 if (logger.isDebugEnabled()) { 513 logger.info("ht(H) = " + H.leadingExpVector()); 514 } 515 516 H = engine.recursivePrimitivePart(H); //H.monic(); 517 H = H.abs(); 518 // System.out.println("H = " + H); 519 if (H.isONE()) { 520 // putOne not required 521 pairlist.put(H); 522 synchronized (G) { 523 G.clear(); 524 G.add(H); 525 } 526 fin.allIdle(); 527 return; 528 } 529 if (logger.isDebugEnabled()) { 530 logger.debug("H = " + H); 531 } 532 synchronized (G) { 533 G.add(H); 534 } 535 pairlist.put(H); 536 fin.initIdle(1); 537 } 538 fin.allIdle(); 539 logger.info("terminated, done " + reduction + " reductions"); 540 } 541} 542 543 544/** 545 * Pseudo Reducing worker threads for minimal GB. 546 */ 547class PseudoMiReducerRec<C extends GcdRingElem<C>> implements Runnable { 548 549 550 private final List<GenPolynomial<GenPolynomial<C>>> G; 551 552 553 private GenPolynomial<GenPolynomial<C>> H; 554 555 556 //private final PseudoReductionPar<GenPolynomial<C>> red; 557 558 559 private final PseudoReductionPar<C> redRec; 560 561 562 private final Semaphore done = new Semaphore(0); 563 564 565 private final GreatestCommonDivisorAbstract<C> engine; 566 567 568 private static final Logger logger = Logger.getLogger(PseudoMiReducerRec.class); 569 570 571 PseudoMiReducerRec(List<GenPolynomial<GenPolynomial<C>>> G, GenPolynomial<GenPolynomial<C>> p, 572 GreatestCommonDivisorAbstract<C> engine) { 573 this.G = G; 574 this.engine = engine; 575 H = p; 576 //red = new PseudoReductionPar<GenPolynomial<C>>(); 577 redRec = new PseudoReductionPar<C>(); 578 } 579 580 581 /** 582 * to string 583 */ 584 @Override 585 public String toString() { 586 return "PseudoMiReducerRec"; 587 } 588 589 590 /** 591 * getNF. Blocks until the normal form is computed. 592 * @return the computed normal form. 593 */ 594 public GenPolynomial<GenPolynomial<C>> getNF() { 595 try { 596 done.acquire(); //done.P(); 597 } catch (InterruptedException e) { 598 throw new RuntimeException("interrupt in getNF"); 599 } 600 return H; 601 } 602 603 604 public void run() { 605 if (logger.isDebugEnabled()) { 606 logger.debug("ht(H) = " + H.leadingExpVector()); 607 } 608 try { 609 //H = red.normalform(G, H); //mod 610 H = redRec.normalformRecursive(G, H); 611 H = engine.recursivePrimitivePart(H); //H.monic(); 612 H = H.abs(); 613 done.release(); //done.V(); 614 } catch (RuntimeException e) { 615 Thread.currentThread().interrupt(); 616 //throw new RuntimeException("interrupt in getNF"); 617 } 618 if (logger.isDebugEnabled()) { 619 logger.debug("ht(H) = " + H.leadingExpVector()); 620 } 621 // H = H.monic(); 622 } 623 624}