001    /*
002     * $Id: GroebnerBaseDistributed.java 3626 2011-05-08 09:51:57Z kredel $
003     */
004    
005    package edu.jas.gb;
006    
007    
008    import java.io.IOException;
009    import java.io.Serializable;
010    import java.util.ArrayList;
011    import java.util.List;
012    import java.util.ListIterator;
013    import java.util.Collections;
014    import java.util.concurrent.Semaphore;
015    
016    import org.apache.log4j.Logger;
017    
018    import edu.jas.poly.ExpVector;
019    import edu.jas.poly.GenPolynomial;
020    
021    import edu.jas.structure.RingElem;
022    
023    import edu.jas.util.DistHashTable;
024    import edu.jas.util.DistHashTableServer;
025    import edu.jas.util.Terminator;
026    import edu.jas.util.ThreadPool;
027    import edu.jas.util.ChannelFactory;
028    import edu.jas.util.SocketChannel;
029    
030    
031    /**
032     * Groebner Base distributed algorithm. Implements a distributed memory parallel
033     * version of Groebner bases. Using pairlist class,
034     * distributed tasks do reduction, one communication channel per task.
035     * @param <C> coefficient type
036     * @author Heinz Kredel
037     */
038    
039    public class GroebnerBaseDistributed<C extends RingElem<C>> extends GroebnerBaseAbstract<C> {
040    
041    
042        private static final Logger logger = Logger.getLogger(GroebnerBaseDistributed.class);
043    
044    
045        /**
046         * Number of threads to use.
047         */
048        protected final int threads;
049    
050    
051        /**
052         * Default number of threads.
053         */
054        protected static final int DEFAULT_THREADS = 2;
055    
056    
057        /**
058         * Pool of threads to use. <b>Note:</b> No ComputerThreads for one node
059         * tests
060         */
061        protected final ThreadPool pool;
062    
063    
064        /**
065         * Default server port.
066         */
067        protected static final int DEFAULT_PORT = 4711;
068    
069    
070        /**
071         * Server port to use.
072         */
073        protected final int port;
074    
075    
076        /**
077         * Constructor.
078         */
079        public GroebnerBaseDistributed() {
080            this(DEFAULT_THREADS, DEFAULT_PORT);
081        }
082    
083    
084        /**
085         * Constructor.
086         * @param threads number of threads to use.
087         */
088        public GroebnerBaseDistributed(int threads) {
089            this(threads, new ThreadPool(threads), DEFAULT_PORT);
090        }
091    
092    
093        /**
094         * Constructor.
095         * @param threads number of threads to use.
096         * @param port server port to use.
097         */
098        public GroebnerBaseDistributed(int threads, int port) {
099            this(threads, new ThreadPool(threads), port);
100        }
101    
102    
103        /**
104         * Constructor.
105         * @param threads number of threads to use.
106         * @param pool ThreadPool to use.
107         * @param port server port to use.
108         */
109        public GroebnerBaseDistributed(int threads, ThreadPool pool, int port) {
110            this(threads,pool,new OrderedPairlist<C>(),port);
111        }
112    
113        /**
114         * Constructor.
115         * @param threads number of threads to use.
116         * @param pl pair selection strategy
117         * @param port server port to use.
118         */
119        public GroebnerBaseDistributed(int threads, PairList<C> pl, int port) {
120            this(threads, new ThreadPool(threads), pl , port);
121        }
122    
123        /**
124         * Constructor.
125         * @param threads number of threads to use.
126         * @param pool ThreadPool to use.
127         * @param pl pair selection strategy
128         * @param port server port to use.
129         */
130        public GroebnerBaseDistributed(int threads, ThreadPool pool, PairList<C> pl, int port) {
131            super( new ReductionPar<C>(), pl );
132            if (threads < 1) {
133                threads = 1;
134            }
135            this.threads = threads;
136            this.pool = pool;
137            this.port = port;
138        }
139    
140    
141        /**
142         * Cleanup and terminate ThreadPool.
143         */
144        public void terminate() {
145            if (pool == null) {
146                return;
147            }
148            pool.terminate();
149        }
150    
151    
152        /**
153         * Distributed Groebner base. 
154         * @param modv number of module variables.
155         * @param F polynomial list.
156         * @return GB(F) a Groebner base of F or null, if a IOException occurs.
157         */
158        public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) {
159    
160            final int DL_PORT = port + 100;
161            ChannelFactory cf = new ChannelFactory(port);
162            cf.init();
163            DistHashTableServer<Integer> dls = new DistHashTableServer<Integer>(DL_PORT);
164            dls.init();
165            logger.debug("dist-list server running");
166    
167            GenPolynomial<C> p;
168            List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>();
169            PairList<C> pairlist = null;
170            boolean oneInGB = false;
171            int l = F.size();
172            int unused;
173            ListIterator<GenPolynomial<C>> it = F.listIterator();
174            while (it.hasNext()) {
175                p = it.next();
176                if (p.length() > 0) {
177                    p = p.monic();
178                    if (p.isONE()) {
179                        oneInGB = true;
180                        G.clear();
181                        G.add(p);
182                        //return G; must signal termination to others
183                    }
184                    if (!oneInGB) {
185                        G.add(p);
186                    }
187                    if (pairlist == null) {
188                        //pairlist = new OrderedPairlist<C>(modv, p.ring);
189                        pairlist = strategy.create( modv, p.ring );
190                        if ( ! p.ring.coFac.isField() ) {
191                            throw new IllegalArgumentException("coefficients not from a field");
192                        }
193                    }
194                    // theList not updated here
195                    if (p.isONE()) {
196                        unused = pairlist.putOne();
197                    } else {
198                        unused = pairlist.put(p);
199                    }
200                } else {
201                    l--;
202                }
203            }
204            if (l <= 1) {
205                //return G; must signal termination to others
206            }
207    
208            logger.debug("looking for clients");
209            //long t = System.currentTimeMillis();
210            // now in DL, uses resend for late clients
211            //while ( dls.size() < threads ) { sleep(); }
212    
213            DistHashTable<Integer, GenPolynomial<C>> theList = new DistHashTable<Integer, GenPolynomial<C>>(
214                    "localhost", DL_PORT);
215            List<GenPolynomial<C>> al = pairlist.getList();
216            for (int i = 0; i < al.size(); i++) {
217                // no wait required
218                GenPolynomial<C> nn = theList.put(new Integer(i), al.get(i));
219                if (nn != null) {
220                    logger.info("double polynomials " + i + ", nn = " + nn + ", al(i) = " + al.get(i));
221                }
222            }
223    
224            Terminator fin = new Terminator(threads);
225            ReducerServer<C> R;
226            for (int i = 0; i < threads; i++) {
227                R = new ReducerServer<C>(fin, cf, theList, G, pairlist);
228                pool.addJob(R);
229            }
230            logger.debug("main loop waiting");
231            fin.waitDone();
232            int ps = theList.size();
233            logger.debug("#distributed list = " + ps);
234            // make sure all polynomials arrived: not needed in master
235            // G = (ArrayList)theList.values();
236            G = pairlist.getList();
237            if (ps != G.size()) {
238                logger.info("#distributed list = " + theList.size() + " #pairlist list = " + G.size());
239            }
240            long time = System.currentTimeMillis();
241            List<GenPolynomial<C>> Gp;
242            Gp = minimalGB(G); // not jet distributed but threaded
243            time = System.currentTimeMillis() - time;
244            logger.info("parallel gbmi = " + time);
245            /*
246            time = System.currentTimeMillis();
247            G = GroebnerBase.<C>GBmi(G); // sequential
248            time = System.currentTimeMillis() - time;
249            logger.info("sequential gbmi = " + time);
250            */
251            G = Gp;
252            logger.debug("cf.terminate()");
253            cf.terminate();
254            // no more required // pool.terminate();
255            logger.info("theList.terminate()");
256            theList.terminate();
257            logger.info("dls.terminate()");
258            dls.terminate();
259            logger.info("" + pairlist); 
260            return G;
261        }
262    
263    
264        /**
265         * GB distributed client.
266         * @param host the server runns on.
267         * @throws IOException
268         */
269        public void clientPart(String host) throws IOException {
270    
271            ChannelFactory cf = new ChannelFactory(port + 10); // != port for localhost
272            cf.init();
273            SocketChannel pairChannel = cf.getChannel(host, port);
274    
275            final int DL_PORT = port + 100;
276            DistHashTable<Integer, GenPolynomial<C>> theList = new DistHashTable<Integer, GenPolynomial<C>>(host,
277                    DL_PORT);
278    
279            ReducerClient<C> R = new ReducerClient<C>(pairChannel, theList);
280            R.run();
281    
282            pairChannel.close();
283            theList.terminate();
284            cf.terminate();
285            return;
286        }
287    
288    
289        /**
290         * Minimal ordered groebner basis.
291         * @param Fp a Groebner base.
292         * @return a reduced Groebner base of Fp.
293         */
294        @Override
295        public List<GenPolynomial<C>> minimalGB(List<GenPolynomial<C>> Fp) {
296            GenPolynomial<C> a;
297            ArrayList<GenPolynomial<C>> G;
298            G = new ArrayList<GenPolynomial<C>>(Fp.size());
299            ListIterator<GenPolynomial<C>> it = Fp.listIterator();
300            while (it.hasNext()) {
301                a = it.next();
302                if (a.length() != 0) { // always true
303                    // already monic  a = a.monic();
304                    G.add(a);
305                }
306            }
307            if (G.size() <= 1) {
308                return G;
309            }
310    
311            ExpVector e;
312            ExpVector f;
313            GenPolynomial<C> p;
314            ArrayList<GenPolynomial<C>> F;
315            F = new ArrayList<GenPolynomial<C>>(G.size());
316            boolean mt;
317    
318            while (G.size() > 0) {
319                a = G.remove(0);
320                e = a.leadingExpVector();
321    
322                it = G.listIterator();
323                mt = false;
324                while (it.hasNext() && !mt) {
325                    p = it.next();
326                    f = p.leadingExpVector();
327                    mt = e.multipleOf(f);
328                }
329                it = F.listIterator();
330                while (it.hasNext() && !mt) {
331                    p = it.next();
332                    f = p.leadingExpVector();
333                    mt = e.multipleOf(f);
334                }
335                if (!mt) {
336                    F.add(a);
337                } else {
338                    // System.out.println("dropped " + a.length());
339                }
340            }
341            G = F;
342            if (G.size() <= 1) {
343                return G;
344            }
345            Collections.reverse(G); // important for lex GB
346    
347            MiReducerServer<C>[] mirs = (MiReducerServer<C>[]) new MiReducerServer[G.size()];
348            int i = 0;
349            F = new ArrayList<GenPolynomial<C>>(G.size());
350            while (G.size() > 0) {
351                a = G.remove(0);
352                // System.out.println("doing " + a.length());
353                List<GenPolynomial<C>> R = new ArrayList<GenPolynomial<C>>(G.size()+F.size());
354                R.addAll(G);
355                R.addAll(F);
356                mirs[i] = new MiReducerServer<C>(R, a);
357                pool.addJob(mirs[i]);
358                i++;
359                F.add(a);
360            }
361            G = F;
362            F = new ArrayList<GenPolynomial<C>>(G.size());
363            for (i = 0; i < mirs.length; i++) {
364                a = mirs[i].getNF();
365                F.add(a);
366            }
367            return F;
368        }
369    
370    }
371    
372    
373    /**
374     * Distributed server reducing worker threads.
375     * @param <C> coefficient type
376     */
377    
378    class ReducerServer<C extends RingElem<C>> implements Runnable {
379    
380    
381        private final Terminator pool;
382    
383    
384        private final ChannelFactory cf;
385    
386    
387        private SocketChannel pairChannel;
388    
389    
390        private final DistHashTable<Integer, GenPolynomial<C>> theList;
391    
392    
393        //private List<GenPolynomial<C>> G;
394        private final PairList<C> pairlist;
395    
396    
397        private static final Logger logger = Logger.getLogger(ReducerServer.class);
398    
399    
400        ReducerServer(Terminator fin, ChannelFactory cf, DistHashTable<Integer, GenPolynomial<C>> dl,
401                List<GenPolynomial<C>> G, PairList<C> L) {
402            pool = fin;
403            this.cf = cf;
404            theList = dl;
405            //this.G = G;
406            pairlist = L;
407        }
408    
409    
410        public void run() {
411            logger.debug("reducer server running");
412            try {
413                pairChannel = cf.getChannel();
414            } catch (InterruptedException e) {
415                logger.debug("get pair channel interrupted");
416                e.printStackTrace();
417                return;
418            }
419            if (logger.isDebugEnabled()) {
420                logger.debug("pairChannel = " + pairChannel);
421            }
422            Pair<C> pair;
423            //GenPolynomial<C> pi;
424            //GenPolynomial<C> pj;
425            //GenPolynomial<C> S;
426            GenPolynomial<C> H = null;
427            boolean set = false;
428            boolean goon = true;
429            int polIndex = -1;
430            int red = 0;
431            int sleeps = 0;
432    
433            // while more requests
434            while (goon) {
435                // receive request
436                logger.debug("receive request");
437                Object req = null;
438                try {
439                    req = pairChannel.receive();
440                } catch (IOException e) {
441                    goon = false;
442                    e.printStackTrace();
443                } catch (ClassNotFoundException e) {
444                    goon = false;
445                    e.printStackTrace();
446                }
447                //logger.debug("received request, req = " + req);
448                if (req == null) {
449                    goon = false;
450                    break;
451                }
452                if (!(req instanceof GBTransportMessReq)) {
453                    goon = false;
454                    break;
455                }
456    
457                // find pair
458                logger.debug("find pair");
459                while (!pairlist.hasNext()) { // wait
460                    if (!set) {
461                        pool.beIdle();
462                        set = true;
463                    }
464                    if (!pool.hasJobs() && !pairlist.hasNext()) {
465                        goon = false;
466                        break;
467                    }
468                    try {
469                        sleeps++;
470                        if (sleeps % 10 == 0) {
471                            logger.info(" reducer is sleeping");
472                        }
473                        Thread.sleep(100);
474                    } catch (InterruptedException e) {
475                        goon = false;
476                        break;
477                    }
478                }
479                if (!pairlist.hasNext() && !pool.hasJobs()) {
480                    goon = false;
481                    break; //continue; //break?
482                }
483                if (set) {
484                    set = false;
485                    pool.notIdle();
486                }
487    
488                pair = pairlist.removeNext();
489                /*
490                 * send pair to client, receive H
491                 */
492                logger.debug("send pair = " + pair);
493                GBTransportMess msg = null;
494                if (pair != null) {
495                    msg = new GBTransportMessPairIndex(pair);
496                } else {
497                    msg = new GBTransportMess(); //End();
498                    // goon ?= false;
499                }
500                try {
501                    pairChannel.send(msg);
502                } catch (IOException e) {
503                    e.printStackTrace();
504                    goon = false;
505                    break;
506                }
507                logger.debug("#distributed list = " + theList.size());
508                Object rh = null;
509                try {
510                    rh = pairChannel.receive();
511                } catch (IOException e) {
512                    e.printStackTrace();
513                    goon = false;
514                    break;
515                } catch (ClassNotFoundException e) {
516                    e.printStackTrace();
517                    goon = false;
518                    break;
519                }
520                //logger.debug("received H polynomial");
521                if (rh == null) {
522                    if (pair != null) {
523                        pair.setZero();
524                    }
525                } else if (rh instanceof GBTransportMessPoly) {
526                    // update pair list
527                    red++;
528                    H = ((GBTransportMessPoly<C>) rh).pol;
529                    if (logger.isDebugEnabled()) {
530                        logger.debug("H = " + H);
531                    }
532                    if (H == null) {
533                        if (pair != null) {
534                            pair.setZero();
535                        }
536                    } else {
537                        if (H.isZERO()) {
538                            pair.setZero();
539                        } else {
540                            if (H.isONE()) {
541                                // pool.allIdle();
542                                polIndex = pairlist.putOne();
543                                GenPolynomial<C> nn = theList.put(new Integer(polIndex), H);
544                                if (nn != null) {
545                                    logger.info("double polynomials nn = " + nn + ", H = " + H);
546                                }
547                                goon = false;
548                                break;
549                            } else {
550                                polIndex = pairlist.put(H);
551                                // use putWait ? but still not all distributed
552                                GenPolynomial<C> nn = theList.put(new Integer(polIndex), H);
553                                if (nn != null) {
554                                    logger.info("double polynomials nn = " + nn + ", H = " + H);
555                                }
556                            }
557                        }
558                    }
559                }
560            }
561            logger.info("terminated, done " + red + " reductions");
562    
563            /*
564             * send end mark to client
565             */
566            logger.debug("send end");
567            try {
568                pairChannel.send(new GBTransportMessEnd());
569            } catch (IOException e) {
570                if (logger.isDebugEnabled()) {
571                    e.printStackTrace();
572                }
573            }
574            pool.beIdle();
575            pairChannel.close();
576        }
577    
578    }
579    
580    
581    /**
582     * Distributed GB transport message.
583     */
584    
585    class GBTransportMess implements Serializable {
586    
587    
588        /**
589         * toString.
590         */
591        @Override
592        public String toString() {
593            return "" + this.getClass().getName();
594        }
595    }
596    
597    
598    /**
599     * Distributed GB transport message for requests.
600     */
601    
602    class GBTransportMessReq extends GBTransportMess {
603    
604    
605        public GBTransportMessReq() {
606        }
607    }
608    
609    
610    /**
611     * Distributed GB transport message for termination.
612     */
613    
614    class GBTransportMessEnd extends GBTransportMess {
615    
616    
617        public GBTransportMessEnd() {
618        }
619    }
620    
621    
622    /**
623     * Distributed GB transport message for polynomial.
624     */
625    
626    class GBTransportMessPoly<C extends RingElem<C>> extends GBTransportMess {
627    
628    
629        /**
630         * The polynomial for transport.
631         */
632        public final GenPolynomial<C> pol;
633    
634    
635        /**
636         * GBTransportMessPoly.
637         * @param p polynomial to transfered.
638         */
639        public GBTransportMessPoly(GenPolynomial<C> p) {
640            this.pol = p;
641        }
642    
643    
644        /**
645         * toString.
646         */
647        @Override
648        public String toString() {
649            return super.toString() + "( " + pol + " )";
650        }
651    }
652    
653    
654    /**
655     * Distributed GB transport message for pairs.
656     */
657    
658    class GBTransportMessPair<C extends RingElem<C>> extends GBTransportMess {
659    
660    
661        public final Pair<C> pair;
662    
663    
664        /**
665         * GBTransportMessPair.
666         * @param p pair for transfer.
667         */
668        public GBTransportMessPair(Pair<C> p) {
669            this.pair = p;
670        }
671    
672    
673        /**
674         * toString.
675         */
676        @Override
677        public String toString() {
678            return super.toString() + "( " + pair + " )";
679        }
680    }
681    
682    
683    /**
684     * Distributed GB transport message for index pairs.
685     */
686    
687    class GBTransportMessPairIndex extends GBTransportMess {
688    
689    
690        public final Integer i;
691    
692    
693        public final Integer j;
694    
695    
696        /**
697         * GBTransportMessPairIndex.
698         * @param p pair for transport.
699         */
700        public GBTransportMessPairIndex(Pair p) {
701            if (p == null) {
702                throw new NullPointerException("pair may not be null");
703            }
704            this.i = new Integer(p.i);
705            this.j = new Integer(p.j);
706        }
707    
708    
709        /**
710         * GBTransportMessPairIndex.
711         * @param i first index.
712         * @param j second index.
713         */
714        public GBTransportMessPairIndex(int i, int j) {
715            this.i = new Integer(i);
716            this.j = new Integer(j);
717        }
718    
719    
720        /**
721         * GBTransportMessPairIndex.
722         * @param i first index.
723         * @param j second index.
724         */
725        public GBTransportMessPairIndex(Integer i, Integer j) {
726            this.i = i;
727            this.j = j;
728        }
729    
730    
731        /**
732         * toString.
733         */
734        @Override
735        public String toString() {
736            return super.toString() + "( " + i + "," + j + " )";
737        }
738    }
739    
740    
741    /**
742     * Distributed clients reducing worker threads.
743     */
744    
745    class ReducerClient<C extends RingElem<C>> implements Runnable {
746    
747    
748        private final SocketChannel pairChannel;
749    
750    
751        private final DistHashTable<Integer, GenPolynomial<C>> theList;
752    
753    
754        private final ReductionPar<C> red;
755    
756    
757        private static final Logger logger = Logger.getLogger(ReducerClient.class);
758    
759    
760        ReducerClient(SocketChannel pc, DistHashTable<Integer, GenPolynomial<C>> dl) {
761            pairChannel = pc;
762            theList = dl;
763            red = new ReductionPar<C>();
764        }
765    
766    
767        public void run() {
768            logger.debug("pairChannel = " + pairChannel + " reducer client running");
769            Pair<C> pair = null;
770            GenPolynomial<C> pi;
771            GenPolynomial<C> pj;
772            GenPolynomial<C> S;
773            GenPolynomial<C> H = null;
774            //boolean set = false;
775            boolean goon = true;
776            int reduction = 0;
777            //int sleeps = 0;
778            Integer pix;
779            Integer pjx;
780    
781            while (goon) {
782                /* protocol:
783                 * request pair, process pair, send result
784                 */
785                // pair = (Pair) pairlist.removeNext();
786                Object req = new GBTransportMessReq();
787                logger.debug("send request = " + req);
788                try {
789                    pairChannel.send(req);
790                } catch (IOException e) {
791                    goon = false;
792                    e.printStackTrace();
793                    break;
794                }
795                logger.debug("receive pair, goon = " + goon);
796                Object pp = null;
797                try {
798                    pp = pairChannel.receive();
799                } catch (IOException e) {
800                    goon = false;
801                    if (logger.isDebugEnabled()) {
802                        e.printStackTrace();
803                    }
804                    break;
805                } catch (ClassNotFoundException e) {
806                    goon = false;
807                    e.printStackTrace();
808                }
809                if (logger.isDebugEnabled()) {
810                    logger.debug("received pair = " + pp);
811                }
812                H = null;
813                if (pp == null) { // should not happen
814                    continue;
815                }
816                if (pp instanceof GBTransportMessEnd) {
817                    goon = false;
818                    continue;
819                }
820                if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) {
821                    pi = pj = null;
822                    if (pp instanceof GBTransportMessPair) {
823                        pair = ((GBTransportMessPair<C>) pp).pair;
824                        if (pair != null) {
825                            pi = pair.pi;
826                            pj = pair.pj;
827                            //logger.debug("pair: pix = " + pair.i 
828                            //               + ", pjx = " + pair.j);
829                        }
830                    }
831                    if (pp instanceof GBTransportMessPairIndex) {
832                        pix = ((GBTransportMessPairIndex) pp).i;
833                        pjx = ((GBTransportMessPairIndex) pp).j;
834                        pi = (GenPolynomial<C>) theList.getWait(pix);
835                        pj = (GenPolynomial<C>) theList.getWait(pjx);
836                        //logger.info("pix = " + pix + ", pjx = " +pjx);
837                    }
838    
839                    if (pi != null && pj != null) {
840                        S = red.SPolynomial(pi, pj);
841                        //System.out.println("S   = " + S);
842                        if (S.isZERO()) {
843                            // pair.setZero(); does not work in dist
844                        } else {
845                            if (logger.isDebugEnabled()) {
846                                logger.debug("ht(S) = " + S.leadingExpVector());
847                            }
848                            H = red.normalform(theList, S);
849                            reduction++;
850                            if (H.isZERO()) {
851                                // pair.setZero(); does not work in dist
852                            } else {
853                                H = H.monic();
854                                if (logger.isInfoEnabled()) {
855                                    logger.info("ht(H) = " + H.leadingExpVector());
856                                }
857                            }
858                        }
859                    }
860                }
861    
862                // send H or must send null
863                if (logger.isDebugEnabled()) {
864                    logger.debug("#distributed list = " + theList.size());
865                    logger.debug("send H polynomial = " + H);
866                }
867                try {
868                    pairChannel.send(new GBTransportMessPoly<C>(H));
869                } catch (IOException e) {
870                    goon = false;
871                    e.printStackTrace();
872                }
873            }
874            logger.info("terminated, done " + reduction + " reductions");
875            pairChannel.close();
876        }
877    }
878    
879    
880    /**
881     * Distributed server reducing worker threads for minimal GB Not jet distributed
882     * but threaded.
883     */
884    
885    class MiReducerServer<C extends RingElem<C>> implements Runnable {
886    
887    
888        private final List<GenPolynomial<C>> G;
889    
890    
891        private GenPolynomial<C> H;
892    
893    
894        private final Semaphore done = new Semaphore(0);
895    
896    
897        private final Reduction<C> red;
898    
899    
900        private static final Logger logger = Logger.getLogger(MiReducerServer.class);
901    
902    
903        MiReducerServer(List<GenPolynomial<C>> G, GenPolynomial<C> p) {
904            this.G = G;
905            H = p;
906            red = new ReductionPar<C>();
907        }
908    
909    
910        /**
911         * getNF. Blocks until the normal form is computed.
912         * @return the computed normal form.
913         */
914        public GenPolynomial<C> getNF() {
915            try {
916                done.acquire(); //done.P();
917            } catch (InterruptedException e) {
918            }
919            return H;
920        }
921    
922    
923        public void run() {
924            if (logger.isDebugEnabled()) {
925                logger.debug("ht(H) = " + H.leadingExpVector());
926            }
927            H = red.normalform(G, H); //mod
928            done.release(); //done.V();
929            if (logger.isDebugEnabled()) {
930                logger.debug("ht(H) = " + H.leadingExpVector());
931            }
932            // H = H.monic();
933        }
934    }
935    
936    
937    /**
938     * Distributed clients reducing worker threads for minimal GB. Not jet used.
939     */
940    
941    class MiReducerClient<C extends RingElem<C>> implements Runnable {
942    
943    
944        private final List<GenPolynomial<C>> G;
945    
946    
947        private GenPolynomial<C> H;
948    
949    
950        private final Reduction<C> red;
951    
952    
953        private final Semaphore done = new Semaphore(0);
954    
955    
956        private static final Logger logger = Logger.getLogger(MiReducerClient.class);
957    
958    
959        MiReducerClient(List<GenPolynomial<C>> G, GenPolynomial<C> p) {
960            this.G = G;
961            H = p;
962            red = new ReductionPar<C>();
963        }
964    
965    
966        /**
967         * getNF. Blocks until the normal form is computed.
968         * @return the computed normal form.
969         */
970        public GenPolynomial<C> getNF() {
971            try {
972                done.acquire(); //done.P();
973            } catch (InterruptedException u) {
974                Thread.currentThread().interrupt();
975            }
976            return H;
977        }
978    
979    
980        public void run() {
981            if (logger.isDebugEnabled()) {
982                logger.debug("ht(S) = " + H.leadingExpVector());
983            }
984            H = red.normalform(G, H); //mod
985            done.release(); //done.V();
986            if (logger.isDebugEnabled()) {
987                logger.debug("ht(H) = " + H.leadingExpVector());
988            }
989            // H = H.monic();
990        }
991    }