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