001 /* 002 * $Id: GroebnerBaseParallel.java 3626 2011-05-08 09:51:57Z kredel $ 003 */ 004 005 package edu.jas.gb; 006 007 import java.util.ArrayList; 008 import java.util.List; 009 import java.util.ListIterator; 010 import java.util.Collections; 011 import java.util.concurrent.Semaphore; 012 013 import org.apache.log4j.Logger; 014 015 import edu.jas.structure.RingElem; 016 017 import edu.jas.gb.OrderedPairlist; 018 import edu.jas.gb.PairList; 019 import edu.jas.poly.ExpVector; 020 import edu.jas.poly.GenPolynomial; 021 022 import edu.jas.util.Terminator; 023 import edu.jas.util.ThreadPool; 024 //import edu.unima.ky.parallel.Semaphore; 025 026 027 /** 028 * Groebner Base parallel algortihm. 029 * Implements a shared memory parallel version of Groebner bases. 030 * @param <C> coefficient type 031 * @author Heinz Kredel 032 */ 033 034 public class GroebnerBaseParallel<C extends RingElem<C>> 035 extends GroebnerBaseAbstract<C> { 036 037 private static final Logger logger = Logger.getLogger(GroebnerBaseParallel.class); 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 final ThreadPool pool; 050 051 052 /** 053 * Constructor. 054 */ 055 public GroebnerBaseParallel() { 056 this(2); 057 } 058 059 060 /** 061 * Constructor. 062 * @param threads number of threads to use. 063 */ 064 public GroebnerBaseParallel(int threads) { 065 this(threads, new ThreadPool(threads) ); 066 } 067 068 069 /** 070 * Constructor. 071 * @param threads number of threads to use. 072 * @param red parallelism aware reduction engine 073 */ 074 public GroebnerBaseParallel(int threads, Reduction<C> red) { 075 this(threads, new ThreadPool(threads), red ); 076 } 077 078 079 /** 080 * Constructor. 081 * @param threads number of threads to use. 082 * @param pool ThreadPool to use. 083 */ 084 public GroebnerBaseParallel(int threads, ThreadPool pool) { 085 this(threads, pool, new ReductionPar<C>() ); 086 } 087 088 089 /** 090 * Constructor. 091 * @param pool ThreadPool to use. 092 * @param red Reduction engine 093 */ 094 public GroebnerBaseParallel(int threads, ThreadPool pool, Reduction<C> red) { 095 this(threads, pool, red, new OrderedPairlist<C>()); 096 } 097 098 099 /** 100 * Constructor. 101 * @param red Reduction engine 102 * @param pl pair selection strategy 103 */ 104 public GroebnerBaseParallel(int threads, Reduction<C> red, PairList<C> pl) { 105 this(threads, new ThreadPool(threads),red,pl); 106 } 107 108 109 /** 110 * Constructor. 111 * @param threads number of threads to use. 112 * @param pool ThreadPool to use. 113 * @param red parallelism aware reduction engine 114 * @param pl pair selection strategy 115 */ 116 public GroebnerBaseParallel(int threads, ThreadPool pool, Reduction<C> red, PairList<C> pl) { 117 super( red, pl ); 118 if ( ! (red instanceof ReductionPar) ) { 119 logger.warn("parallel GB should use parallel aware reduction"); 120 } 121 if ( threads < 1 ) { 122 threads = 1; 123 } 124 this.threads = threads; 125 this.pool = pool; 126 } 127 128 129 /** 130 * Cleanup and terminate ThreadPool. 131 */ 132 public void terminate() { 133 if ( pool == null ) { 134 return; 135 } 136 pool.terminate(); 137 } 138 139 140 /** 141 * Cancel ThreadPool. 142 */ 143 public int cancel() { 144 if ( pool == null ) { 145 return 0; 146 } 147 int s = pool.cancel(); 148 return s; 149 } 150 151 152 /** 153 * Parallel Groebner base using pairlist class. 154 * @param modv number of module variables. 155 * @param F polynomial list. 156 * @return GB(F) a Groebner base of F. 157 */ 158 public List<GenPolynomial<C>> 159 GB( int modv, 160 List<GenPolynomial<C>> F ) { 161 GenPolynomial<C> p; 162 List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>(); 163 PairList<C> pairlist = null; 164 int l = F.size(); 165 ListIterator<GenPolynomial<C>> it = F.listIterator(); 166 while ( it.hasNext() ) { 167 p = it.next(); 168 if ( p.length() > 0 ) { 169 p = p.monic(); 170 if ( p.isONE() ) { 171 G.clear(); G.add( p ); 172 return G; // since no threads activated jet 173 } 174 G.add( p ); 175 if ( pairlist == null ) { 176 //pairlist = new OrderedPairlist<C>( modv, p.ring ); 177 pairlist = strategy.create( modv, p.ring ); 178 if ( ! p.ring.coFac.isField() ) { 179 throw new IllegalArgumentException("coefficients not from a field"); 180 } 181 } 182 // putOne not required 183 pairlist.put( p ); 184 } else { 185 l--; 186 } 187 } 188 if ( l <= 1 ) { 189 return G; // since no threads activated jet 190 } 191 logger.info("start " + pairlist); 192 193 Terminator fin = new Terminator(threads); 194 Reducer<C> R; 195 for ( int i = 0; i < threads; i++ ) { 196 R = new Reducer<C>( fin, G, pairlist ); 197 pool.addJob( R ); 198 } 199 fin.waitDone(); 200 if ( Thread.currentThread().isInterrupted() ) { 201 throw new RuntimeException("interrupt before minimalGB"); 202 } 203 logger.debug("#parallel list = "+G.size()); 204 G = minimalGB(G); 205 // not in this context // pool.terminate(); 206 logger.info("" + pairlist); 207 return G; 208 } 209 210 211 /** 212 * Minimal ordered groebner basis, parallel. 213 * @param Fp a Groebner base. 214 * @return minimalGB(F) a minimal Groebner base of Fp. 215 */ 216 @Override 217 public List<GenPolynomial<C>> minimalGB(List<GenPolynomial<C>> Fp) { 218 GenPolynomial<C> a; 219 ArrayList<GenPolynomial<C>> G; 220 G = new ArrayList<GenPolynomial<C>>( Fp.size() ); 221 ListIterator<GenPolynomial<C>> it = Fp.listIterator(); 222 while ( it.hasNext() ) { 223 a = it.next(); 224 if ( a.length() != 0 ) { // always true 225 // already monic a = a.monic(); 226 G.add( a ); 227 } 228 } 229 if ( G.size() <= 1 ) { 230 return G; 231 } 232 233 ExpVector e; 234 ExpVector f; 235 GenPolynomial<C> p; 236 ArrayList<GenPolynomial<C>> F; 237 F = new ArrayList<GenPolynomial<C>>( G.size() ); 238 boolean mt; 239 while ( G.size() > 0 ) { 240 a = G.remove(0); 241 e = a.leadingExpVector(); 242 243 it = G.listIterator(); 244 mt = false; 245 while ( it.hasNext() && ! mt ) { 246 p = it.next(); 247 f = p.leadingExpVector(); 248 mt = e.multipleOf( f ); 249 } 250 it = F.listIterator(); 251 while ( it.hasNext() && ! mt ) { 252 p = it.next(); 253 f = p.leadingExpVector(); 254 mt = e.multipleOf( f ); 255 } 256 if ( ! mt ) { 257 F.add( a ); // no thread at this point 258 } else { 259 // System.out.println("dropped " + a.length()); 260 } 261 } 262 G = F; 263 if ( G.size() <= 1 ) { 264 return G; 265 } 266 Collections.reverse(G); // important for lex GB 267 268 MiReducer<C>[] mirs = (MiReducer<C>[]) new MiReducer[ G.size() ]; 269 int i = 0; 270 F = new ArrayList<GenPolynomial<C>>( G.size() ); 271 while ( G.size() > 0 ) { 272 a = G.remove(0); 273 List<GenPolynomial<C>> R = new ArrayList<GenPolynomial<C>>(G.size()+F.size()); 274 R.addAll(G); 275 R.addAll(F); 276 // System.out.println("doing " + a.length()); 277 mirs[i] = new MiReducer<C>(R,a); 278 pool.addJob( mirs[i] ); 279 i++; 280 F.add( a ); 281 } 282 G = F; 283 F = new ArrayList<GenPolynomial<C>>( G.size() ); 284 for ( i = 0; i < mirs.length; i++ ) { 285 a = mirs[i].getNF(); 286 F.add( a ); 287 } 288 return F; 289 } 290 291 } 292 293 294 /** 295 * Reducing worker threads. 296 */ 297 class Reducer<C extends RingElem<C>> implements Runnable { 298 private List<GenPolynomial<C>> G; 299 private PairList<C> pairlist; 300 private Terminator fin; 301 private ReductionPar<C> red; 302 private static final Logger logger = Logger.getLogger(Reducer.class); 303 304 Reducer(Terminator fin, 305 List<GenPolynomial<C>> G, 306 PairList<C> L) { 307 this.fin = fin; 308 this.G = G; 309 pairlist = L; 310 red = new ReductionPar<C>(); 311 fin.initIdle(1); 312 } 313 314 315 /** 316 * to string 317 */ 318 @Override 319 public String toString() { 320 return "Reducer"; 321 } 322 323 324 public void run() { 325 Pair<C> pair; 326 GenPolynomial<C> pi; 327 GenPolynomial<C> pj; 328 GenPolynomial<C> S; 329 GenPolynomial<C> H; 330 boolean set = false; 331 int reduction = 0; 332 int sleeps = 0; 333 while ( pairlist.hasNext() || fin.hasJobs() ) { 334 while ( ! pairlist.hasNext() ) { 335 // wait 336 //fin.beIdle(); set = true; 337 try { 338 sleeps++; 339 if ( sleeps % 10 == 0 ) { 340 logger.info(" reducer is sleeping"); 341 } else { 342 logger.debug("r"); 343 } 344 Thread.sleep(100); 345 } catch (InterruptedException e) { 346 break; 347 } 348 if ( ! fin.hasJobs() ) { 349 break; 350 } 351 } 352 if ( ! pairlist.hasNext() && ! fin.hasJobs() ) { 353 break; 354 } 355 //if ( set ) { 356 //fin.notIdle(); set = false; 357 //} 358 359 fin.notIdle(); // before pairlist get 360 pair = pairlist.removeNext(); 361 if ( Thread.currentThread().isInterrupted() ) { 362 fin.initIdle(1); 363 throw new RuntimeException("interrupt after removeNext"); 364 } 365 if ( pair == null ) { 366 fin.initIdle(1); 367 continue; 368 } 369 370 pi = pair.pi; 371 pj = pair.pj; 372 if ( false && logger.isDebugEnabled() ) { 373 logger.debug("pi = " + pi ); 374 logger.debug("pj = " + pj ); 375 } 376 377 S = red.SPolynomial( pi, pj ); 378 if ( S.isZERO() ) { 379 pair.setZero(); 380 fin.initIdle(1); 381 continue; 382 } 383 if ( logger.isDebugEnabled() ) { 384 logger.debug("ht(S) = " + S.leadingExpVector() ); 385 } 386 387 H = red.normalform( G, S ); //mod 388 reduction++; 389 if ( H.isZERO() ) { 390 pair.setZero(); 391 fin.initIdle(1); 392 continue; 393 } 394 if ( logger.isDebugEnabled() ) { 395 logger.debug("ht(H) = " + H.leadingExpVector() ); 396 } 397 398 H = H.monic(); 399 // System.out.println("H = " + H); 400 if ( H.isONE() ) { 401 // putOne not required 402 pairlist.put( H ); 403 synchronized (G) { 404 G.clear(); G.add( H ); 405 } 406 fin.allIdle(); 407 return; 408 } 409 if ( logger.isDebugEnabled() ) { 410 logger.debug("H = " + H ); 411 } 412 synchronized (G) { 413 G.add( H ); 414 } 415 pairlist.put( H ); 416 fin.initIdle(1); 417 } 418 fin.allIdle(); 419 logger.info( "terminated, done " + reduction + " reductions"); 420 } 421 } 422 423 424 /** 425 * Reducing worker threads for minimal GB. 426 */ 427 class MiReducer<C extends RingElem<C>> implements Runnable { 428 private List<GenPolynomial<C>> G; 429 private GenPolynomial<C> H; 430 private ReductionPar<C> red; 431 private Semaphore done = new Semaphore(0); 432 private static final Logger logger = Logger.getLogger(MiReducer.class); 433 434 MiReducer(List<GenPolynomial<C>> G, GenPolynomial<C> p) { 435 this.G = G; 436 H = p; 437 red = new ReductionPar<C>(); 438 } 439 440 441 /** 442 * to string 443 */ 444 @Override 445 public String toString() { 446 return "MiReducer"; 447 } 448 449 450 /** 451 * getNF. Blocks until the normal form is computed. 452 * @return the computed normal form. 453 */ 454 public GenPolynomial<C> getNF() { 455 try { done.acquire(); //done.P(); 456 } catch (InterruptedException e) { 457 throw new RuntimeException("interrupt in getNF"); 458 } 459 return H; 460 } 461 462 public void run() { 463 if ( logger.isDebugEnabled() ) { 464 logger.debug("ht(H) = " + H.leadingExpVector() ); 465 } 466 try { 467 H = red.normalform( G, H ); //mod 468 done.release(); //done.V(); 469 } catch (RuntimeException e) { 470 Thread.currentThread().interrupt(); 471 //throw new RuntimeException("interrupt in getNF"); 472 } 473 if ( logger.isDebugEnabled() ) { 474 logger.debug("ht(H) = " + H.leadingExpVector() ); 475 } 476 // H = H.monic(); 477 } 478 479 } 480