001/* 002 * $Id: GroebnerBasePseudoRecParallel.java 5841 2018-05-20 21:26:13Z 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 static 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("unchecked") 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()) { // remove ? 217 throw new IllegalArgumentException("coefficients from a field"); 218 } 219 PairList<GenPolynomial<C>> pairlist = strategy.create(modv, ring); 220 pairlist.put(G); 221 logger.info("start " + pairlist); 222 223 Terminator fin = new Terminator(threads); 224 PseudoReducerRec<C> R; 225 for (int i = 0; i < threads; i++) { 226 R = new PseudoReducerRec<C>(fin, G, pairlist, engine); 227 pool.addJob(R); 228 } 229 fin.waitDone(); 230 if (Thread.currentThread().isInterrupted()) { 231 throw new RuntimeException("interrupt before minimalGB"); 232 } 233 logger.debug("#parallel list = " + G.size()); 234 G = minimalGB(G); 235 logger.info("" + pairlist); 236 return G; 237 } 238 239 240 /** 241 * Minimal ordered Groebner basis. 242 * @param Gp a Groebner base. 243 * @return a reduced Groebner base of Gp. 244 */ 245 @Override 246 public List<GenPolynomial<GenPolynomial<C>>> minimalGB(List<GenPolynomial<GenPolynomial<C>>> Gp) { 247 List<GenPolynomial<GenPolynomial<C>>> G = normalizeZerosOnes(Gp); 248 if (G.size() <= 1) { 249 return G; 250 } 251 // remove top reducible polynomials 252 GenPolynomial<GenPolynomial<C>> a; 253 List<GenPolynomial<GenPolynomial<C>>> F; 254 F = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size()); 255 while (G.size() > 0) { 256 a = G.remove(0); 257 if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { 258 // drop polynomial 259 if (debug) { 260 System.out.println("dropped " + a); 261 List<GenPolynomial<GenPolynomial<C>>> ff; 262 ff = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G); 263 ff.addAll(F); 264 //a = red.normalform(ff, a); 265 a = redRec.normalformRecursive(ff, a); 266 if (!a.isZERO()) { 267 System.out.println("error, nf(a) " + a); 268 } 269 } 270 } else { 271 F.add(a); 272 } 273 } 274 G = F; 275 if (G.size() <= 1) { 276 return G; 277 } 278 Collections.reverse(G); // important for lex GB 279 // reduce remaining polynomials 280 @SuppressWarnings("unchecked") 281 PseudoMiReducerRec<C>[] mirs = (PseudoMiReducerRec<C>[]) new PseudoMiReducerRec[G.size()]; 282 int i = 0; 283 F = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size()); 284 while (G.size() > 0) { 285 a = G.remove(0); 286 List<GenPolynomial<GenPolynomial<C>>> R = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size() 287 + F.size()); 288 R.addAll(G); 289 R.addAll(F); 290 // System.out.println("doing " + a.length()); 291 mirs[i] = new PseudoMiReducerRec<C>(R, a, engine); 292 pool.addJob(mirs[i]); 293 i++; 294 F.add(a); 295 } 296 G = F; 297 F = new ArrayList<GenPolynomial<GenPolynomial<C>>>(G.size()); 298 for (i = 0; i < mirs.length; i++) { 299 a = mirs[i].getNF(); 300 F.add(a); 301 } 302 Collections.reverse(F); // undo reverse 303 return F; 304 } 305 306 307 /** 308 * Groebner base simple test. 309 * @param modv module variable number. 310 * @param F recursive polynomial list. 311 * @return true, if F is a Groebner base, else false. 312 */ 313 @Override 314 public boolean isGBsimple(int modv, List<GenPolynomial<GenPolynomial<C>>> F) { 315 if (F == null || F.isEmpty()) { 316 return true; 317 } 318 GenPolynomial<GenPolynomial<C>> pi, pj, s, h; 319 ExpVector ei, ej, eij; 320 for (int i = 0; i < F.size(); i++) { 321 pi = F.get(i); 322 ei = pi.leadingExpVector(); 323 for (int j = i + 1; j < F.size(); j++) { 324 pj = F.get(j); 325 ej = pj.leadingExpVector(); 326 if (!red.moduleCriterion(modv, ei, ej)) { 327 continue; 328 } 329 eij = ei.lcm(ej); 330 if (!red.criterion4(ei, ej, eij)) { 331 continue; 332 } 333 //if (!criterion3(i, j, eij, F)) { 334 // continue; 335 //} 336 s = red.SPolynomial(pi, pj); 337 if (s.isZERO()) { 338 continue; 339 } 340 //System.out.println("i, j = " + i + ", " + j); 341 h = redRec.normalformRecursive(F, s); 342 if (!h.isZERO()) { 343 logger.info("no GB: pi = " + pi + ", pj = " + pj); 344 logger.info("s = " + s + ", h = " + h); 345 return false; 346 } 347 } 348 } 349 return true; 350 } 351 352} 353 354 355/** 356 * Pseudo GB Reducing worker threads. 357 */ 358class PseudoReducerRec<C extends GcdRingElem<C>> implements Runnable { 359 360 361 private final List<GenPolynomial<GenPolynomial<C>>> G; 362 363 364 private final PairList<GenPolynomial<C>> pairlist; 365 366 367 private final Terminator fin; 368 369 370 private final PseudoReductionPar<GenPolynomial<C>> red; 371 372 373 private final PseudoReductionPar<C> redRec; 374 375 376 private final GreatestCommonDivisorAbstract<C> engine; 377 378 379 private static final Logger logger = Logger.getLogger(PseudoReducerRec.class); 380 381 382 PseudoReducerRec(Terminator fin, List<GenPolynomial<GenPolynomial<C>>> G, PairList<GenPolynomial<C>> L, 383 GreatestCommonDivisorAbstract<C> engine) { 384 this.fin = fin; 385 this.G = G; 386 pairlist = L; 387 red = new PseudoReductionPar<GenPolynomial<C>>(); 388 redRec = new PseudoReductionPar<C>(); 389 this.engine = engine; 390 fin.initIdle(1); 391 } 392 393 394 /** 395 * to string 396 */ 397 @Override 398 public String toString() { 399 return "PseudoReducer"; 400 } 401 402 403 public void run() { 404 Pair<GenPolynomial<C>> pair; 405 GenPolynomial<GenPolynomial<C>> pi, pj, S, H; 406 //boolean set = false; 407 int reduction = 0; 408 int sleeps = 0; 409 while (pairlist.hasNext() || fin.hasJobs()) { 410 while (!pairlist.hasNext()) { 411 // wait 412 //fin.beIdle(); set = true; 413 try { 414 sleeps++; 415 if (sleeps % 10 == 0) { 416 logger.info(" reducer is sleeping"); 417 } else { 418 logger.debug("r"); 419 } 420 Thread.sleep(100); 421 } catch (InterruptedException e) { 422 break; 423 } 424 if (!fin.hasJobs()) { 425 break; 426 } 427 } 428 if (!pairlist.hasNext() && !fin.hasJobs()) { 429 break; 430 } 431 432 fin.notIdle(); // before pairlist get 433 pair = pairlist.removeNext(); 434 if (Thread.currentThread().isInterrupted()) { 435 fin.initIdle(1); 436 throw new RuntimeException("interrupt after removeNext"); 437 } 438 if (pair == null) { 439 fin.initIdle(1); 440 continue; 441 } 442 443 pi = pair.pi; 444 pj = pair.pj; 445 if (logger.isDebugEnabled()) { 446 logger.debug("pi = " + pi); 447 logger.debug("pj = " + pj); 448 } 449 450 S = red.SPolynomial(pi, pj); 451 if (S.isZERO()) { 452 pair.setZero(); 453 fin.initIdle(1); 454 continue; 455 } 456 if (logger.isDebugEnabled()) { 457 logger.debug("ht(S) = " + S.leadingExpVector()); 458 } 459 460 //H = red.normalform(G, S); //mod 461 H = redRec.normalformRecursive(G, S); 462 reduction++; 463 if (H.isZERO()) { 464 pair.setZero(); 465 fin.initIdle(1); 466 continue; 467 } 468 if (logger.isDebugEnabled()) { 469 logger.info("ht(H) = " + H.leadingExpVector()); 470 } 471 472 H = engine.recursivePrimitivePart(H); //H.monic(); 473 H = H.abs(); 474 // System.out.println("H = " + H); 475 if (H.isONE()) { 476 // putOne not required 477 pairlist.put(H); 478 synchronized (G) { 479 G.clear(); 480 G.add(H); 481 } 482 fin.allIdle(); 483 return; 484 } 485 if (logger.isDebugEnabled()) { 486 logger.debug("H = " + H); 487 } 488 synchronized (G) { 489 G.add(H); 490 } 491 pairlist.put(H); 492 fin.initIdle(1); 493 } 494 fin.allIdle(); 495 logger.info("terminated, done " + reduction + " reductions"); 496 } 497} 498 499 500/** 501 * Pseudo Reducing worker threads for minimal GB. 502 */ 503class PseudoMiReducerRec<C extends GcdRingElem<C>> implements Runnable { 504 505 506 private final List<GenPolynomial<GenPolynomial<C>>> G; 507 508 509 private GenPolynomial<GenPolynomial<C>> H; 510 511 512 //private final PseudoReductionPar<GenPolynomial<C>> red; 513 514 515 private final PseudoReductionPar<C> redRec; 516 517 518 private final Semaphore done = new Semaphore(0); 519 520 521 private final GreatestCommonDivisorAbstract<C> engine; 522 523 524 private static final Logger logger = Logger.getLogger(PseudoMiReducerRec.class); 525 526 527 PseudoMiReducerRec(List<GenPolynomial<GenPolynomial<C>>> G, GenPolynomial<GenPolynomial<C>> p, 528 GreatestCommonDivisorAbstract<C> engine) { 529 this.G = G; 530 this.engine = engine; 531 H = p; 532 //red = new PseudoReductionPar<GenPolynomial<C>>(); 533 redRec = new PseudoReductionPar<C>(); 534 } 535 536 537 /** 538 * to string 539 */ 540 @Override 541 public String toString() { 542 return "PseudoMiReducerRec"; 543 } 544 545 546 /** 547 * getNF. Blocks until the normal form is computed. 548 * @return the computed normal form. 549 */ 550 public GenPolynomial<GenPolynomial<C>> getNF() { 551 try { 552 done.acquire(); //done.P(); 553 } catch (InterruptedException e) { 554 throw new RuntimeException("interrupt in getNF"); 555 } 556 return H; 557 } 558 559 560 public void run() { 561 if (logger.isDebugEnabled()) { 562 logger.debug("ht(H) = " + H.leadingExpVector()); 563 } 564 try { 565 //H = red.normalform(G, H); //mod 566 H = redRec.normalformRecursive(G, H); 567 H = engine.recursivePrimitivePart(H); //H.monic(); 568 H = H.abs(); 569 done.release(); //done.V(); 570 } catch (RuntimeException e) { 571 Thread.currentThread().interrupt(); 572 //throw new RuntimeException("interrupt in getNF"); 573 } 574 if (logger.isDebugEnabled()) { 575 logger.debug("ht(H) = " + H.leadingExpVector()); 576 } 577 // H = H.monic(); 578 } 579 580}