001    /*
002     * $Id: GroebnerBaseSeqPairParallel.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.poly.ExpVector;
018    import edu.jas.poly.GenPolynomial;
019    
020    import edu.jas.util.Terminator;
021    import edu.jas.util.ThreadPool;
022    //import edu.unima.ky.parallel.Semaphore;
023    
024    
025    /**
026     * Groebner Base parallel algorithm.
027     * Makes some effort to produce the same sequence of critical pairs 
028     * as in the sequential version.
029     * However already reduced pairs are not rereduced if new
030     * polynomials appear.
031     * Implements a shared memory parallel version of Groebner bases.
032     * Slaves maintain pairlist.
033     * @param <C> coefficient type
034     * @author Heinz Kredel
035     */
036    
037    public class GroebnerBaseSeqPairParallel<C extends RingElem<C>>
038                 extends GroebnerBaseAbstract<C>  {
039    
040        private static final Logger logger = Logger.getLogger(GroebnerBaseSeqPairParallel.class);
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 final ThreadPool pool;
053    
054    
055        /**
056         * Constructor.
057         */
058        public GroebnerBaseSeqPairParallel() {
059            this(2);
060        }
061    
062    
063        /**
064         * Constructor.
065         * @param threads number of threads to use.
066         */
067        public GroebnerBaseSeqPairParallel(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 GroebnerBaseSeqPairParallel(int threads, ThreadPool pool) {
078            this(threads, pool, new ReductionPar<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 GroebnerBaseSeqPairParallel(int threads, Reduction<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 red parallelism aware reduction engine
097         */
098        public GroebnerBaseSeqPairParallel(int threads, ThreadPool pool, Reduction<C> red) {
099            super(red);
100            if ( ! (red instanceof ReductionPar) ) {
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         * Cancel ThreadPool.
124         */
125        public int cancel() {
126            if ( pool == null ) {
127               return 0;
128            }
129            int s = pool.cancel();
130            return s;
131        }
132    
133    
134        /**
135         * Parallel Groebner base using sequential pair order class.
136         * Slaves maintain pairlist.
137         * @param modv number of module variables.
138         * @param F polynomial list.
139         * @return GB(F) a Groebner base of F.
140         */
141        public List<GenPolynomial<C>> 
142            GB( int modv,
143                List<GenPolynomial<C>> F ) {  
144            GenPolynomial<C> p;
145            List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>();
146            CriticalPairList<C> pairlist = null; 
147            int l = F.size();
148            ListIterator<GenPolynomial<C>> it = F.listIterator();
149            while ( it.hasNext() ) { 
150                p = it.next();
151                if ( p.length() > 0 ) {
152                    p = p.monic();
153                    if ( p.isONE() ) {
154                        G.clear(); G.add( p );
155                        return G; // since no threads activated jet
156                    }
157                    G.add( p );
158                    if ( pairlist == null ) {
159                        pairlist = new CriticalPairList<C>( modv, p.ring );
160                        if ( ! p.ring.coFac.isField() ) {
161                            throw new IllegalArgumentException("coefficients not from a field");
162                        }
163                    }
164                    // putOne not required
165                    pairlist.put( p );
166                } else {
167                    l--;
168                }
169            }
170            if ( l <= 1 ) {
171                return G; // since no threads activated jet
172            }
173    
174            Terminator fin = new Terminator(threads);
175            ReducerSeqPair<C> R;
176            for ( int i = 0; i < threads; i++ ) {
177                R = new ReducerSeqPair<C>( fin, G, pairlist );
178                pool.addJob( R );
179            }
180            fin.waitDone();
181            if ( Thread.currentThread().isInterrupted() ) {
182                throw new RuntimeException("interrupt before minimalGB");
183            }
184            logger.debug("#parallel list = "+G.size());
185            G = minimalGB(G);
186            // not in this context // pool.terminate();
187            logger.info("" + pairlist); 
188            return G;
189        }
190    
191    
192        /**
193         * Minimal ordered groebner basis, parallel.
194         * @param Fp a Groebner base.
195         * @return minimalGB(F) a minimal Groebner base of Fp.
196         */
197        @Override
198        public List<GenPolynomial<C>> 
199            minimalGB(List<GenPolynomial<C>> Fp) {  
200            GenPolynomial<C> a;
201            ArrayList<GenPolynomial<C>> G;
202            G = new ArrayList<GenPolynomial<C>>( Fp.size() );
203            ListIterator<GenPolynomial<C>> it = Fp.listIterator();
204            while ( it.hasNext() ) { 
205                a = it.next();
206                if ( a.length() != 0 ) { // always true
207                    // already monic  a = a.monic();
208                    G.add( a );
209                }
210            }
211            if ( G.size() <= 1 ) {
212                return G;
213            }
214    
215            ExpVector e;        
216            ExpVector f;        
217            GenPolynomial<C> p;
218            ArrayList<GenPolynomial<C>> F;
219            F = new ArrayList<GenPolynomial<C>>( G.size() );
220            boolean mt;
221            while ( G.size() > 0 ) {
222                a = G.remove(0);
223                e = a.leadingExpVector();
224    
225                it = G.listIterator();
226                mt = false;
227                while ( it.hasNext() && ! mt ) {
228                    p = it.next();
229                    f = p.leadingExpVector();
230                    mt =  e.multipleOf( f );
231                }
232                it = F.listIterator();
233                while ( it.hasNext() && ! mt ) {
234                    p = it.next();
235                    f = p.leadingExpVector();
236                    mt =  e.multipleOf( f );
237                }
238                if ( ! mt ) {
239                    F.add( a ); // no thread at this point
240                } else {
241                    // System.out.println("dropped " + a.length());
242                }
243            }
244            G = F;
245            if ( G.size() <= 1 ) {
246                return G;
247            }
248            Collections.reverse(G); // important for lex GB
249    
250            MiReducerSeqPair<C>[] mirs = (MiReducerSeqPair<C>[]) new MiReducerSeqPair[ G.size() ];
251            int i = 0;
252            F = new ArrayList<GenPolynomial<C>>( G.size() );
253            while ( G.size() > 0 ) {
254                a = G.remove(0);
255                // System.out.println("doing " + a.length());
256                List<GenPolynomial<C>> R = new ArrayList<GenPolynomial<C>>(G.size()+F.size());
257                R.addAll(G);
258                R.addAll(F);
259                mirs[i] = new MiReducerSeqPair<C>(R,a );
260                pool.addJob( mirs[i] );
261                i++;
262                F.add( a );
263            }
264            G = F;
265            F = new ArrayList<GenPolynomial<C>>( G.size() );
266            for ( i = 0; i < mirs.length; i++ ) {
267                a = mirs[i].getNF();
268                F.add( a );
269            }
270            return F;
271        }
272    
273    }
274    
275    
276    /**
277     * Reducing worker threads.
278     */
279    class ReducerSeqPair<C extends RingElem<C>> implements Runnable {
280        private List<GenPolynomial<C>> G;
281        private CriticalPairList<C> pairlist;
282        private Terminator fin;
283        private ReductionPar<C> red;
284        private static final Logger logger = Logger.getLogger(ReducerSeqPair.class);
285    
286        ReducerSeqPair(Terminator fin, 
287                       List<GenPolynomial<C>> G, 
288                       CriticalPairList<C> L) {
289            this.fin = fin;
290            this.G = G;
291            pairlist = L;
292            red = new ReductionPar<C>();
293        } 
294    
295    
296        /**
297         * to string
298         */
299        @Override
300        public String toString() {
301            return "ReducerSeqPair";
302        }
303    
304    
305        public void run() {
306            CriticalPair<C> pair;
307            GenPolynomial<C> S;
308            GenPolynomial<C> H;
309            boolean set = false;
310            int reduction = 0;
311            int sleeps = 0;
312            while ( pairlist.hasNext() || fin.hasJobs() ) {
313                while ( ! pairlist.hasNext() ) {
314                    pairlist.update();
315                    // wait
316                    fin.beIdle(); set = true;
317                    try {
318                        sleeps++;
319                        if ( sleeps % 10 == 0 ) {
320                            logger.info(" reducer is sleeping");
321                        } else {
322                            logger.debug("r");
323                        }
324                        Thread.sleep(100);
325                    } catch (InterruptedException e) {
326                        break;
327                    }
328                    if ( ! fin.hasJobs() ) {
329                        break;
330                    }
331                    if ( Thread.currentThread().isInterrupted() ) {
332                        throw new RuntimeException("interrupt after sleep");
333                    }
334                }
335                if ( ! pairlist.hasNext() && ! fin.hasJobs() ) {
336                    break;
337                }
338                if ( set ) {
339                    fin.notIdle(); set = false;
340                }
341                pair = pairlist.getNext();
342                if ( Thread.currentThread().isInterrupted() ) {
343                    throw new RuntimeException("interrupt after getNext");
344                }
345                if ( pair == null ) {
346                    pairlist.update();
347                    continue; 
348                }
349                if ( false && logger.isDebugEnabled() ) {
350                    logger.debug("pi = " + pair.pi );
351                    logger.debug("pj = " + pair.pj );
352                }
353                S = red.SPolynomial( pair.pi, pair.pj );
354                if ( S.isZERO() ) {
355                    pairlist.record( pair, S );
356                    continue;
357                }
358                if ( logger.isDebugEnabled() ) {
359                    logger.debug("ht(S) = " + S.leadingExpVector() );
360                }
361                H = red.normalform( G, S ); //mod
362                reduction++;
363                if ( H.isZERO() ) {
364                    pairlist.record( pair, H );
365                    continue;
366                }
367                if ( logger.isDebugEnabled() ) {
368                    logger.debug("ht(H) = " + H.leadingExpVector() );
369                }
370                H = H.monic();
371                // System.out.println("H   = " + H);
372                if ( H.isONE() ) { 
373                    // pairlist.update( pair, H );
374                    pairlist.putOne(); // not really required
375                    synchronized (G) {
376                        G.clear(); G.add( H );
377                    }
378                    fin.allIdle();
379                    return;
380                }
381                if ( logger.isDebugEnabled() ) {
382                    logger.debug("H = " + H );
383                }
384                synchronized (G) {
385                    G.add( H );
386                }
387                pairlist.update( pair, H );
388                //pairlist.record( pair, H );
389                //pairlist.update();
390            }
391            logger.info( "terminated, done " + reduction + " reductions");
392        }
393    }
394    
395    
396    /**
397     * Reducing worker threads for minimal GB.
398     */
399    class MiReducerSeqPair<C extends RingElem<C>> implements Runnable {
400        private List<GenPolynomial<C>> G;
401        private GenPolynomial<C> H;
402        private ReductionPar<C> red;
403        private Semaphore done = new Semaphore(0);
404        private static final Logger logger = Logger.getLogger(MiReducerSeqPair.class);
405    
406        MiReducerSeqPair(List<GenPolynomial<C>> G, GenPolynomial<C> p) {
407            this.G = G;
408            H = p;
409            red = new ReductionPar<C>();
410        } 
411    
412    
413        /**
414         * to string
415         */
416        @Override
417        public String toString() {
418            return "MiReducerSeqpair";
419        }
420    
421    
422        /**
423         * getNF. Blocks until the normal form is computed.
424         * @return the computed normal form.
425         */
426        public GenPolynomial<C> getNF() {
427            try { done.acquire(); //done.P();
428            } catch (InterruptedException e) { 
429                throw new RuntimeException("interrupt in getNF");
430            }
431            return H;
432        }
433    
434        public void run() {
435            if ( logger.isDebugEnabled() ) {
436                logger.debug("ht(H) = " + H.leadingExpVector() );
437            }
438            try { 
439                H = red.normalform( G, H ); //mod
440                done.release(); //done.V();
441            } catch (RuntimeException e) { 
442                Thread.currentThread().interrupt();
443                //throw new RuntimeException("interrupt in getNF");
444            }
445            if ( logger.isDebugEnabled() ) {
446                logger.debug("ht(H) = " + H.leadingExpVector() );
447            }
448            // H = H.monic();
449        }
450    
451    }
452