001/*
002 * $Id: GroebnerBaseDistributedHybridEC.java 5869 2018-07-20 15:53:10Z kredel $
003 */
004
005package edu.jas.gb;
006
007
008import java.io.IOException;
009import java.util.ArrayList;
010import java.util.Collections;
011import java.util.List;
012import java.util.ListIterator;
013import java.util.concurrent.atomic.AtomicInteger;
014
015import org.apache.logging.log4j.Logger;
016import org.apache.logging.log4j.LogManager; 
017
018import edu.jas.poly.ExpVector;
019import edu.jas.poly.GenPolynomial;
020import edu.jas.poly.GenPolynomialRing;
021import edu.jas.poly.PolyUtil;
022import edu.jas.structure.RingElem;
023import edu.jas.util.ChannelFactory;
024import edu.jas.util.DistHashTable;
025import edu.jas.util.DistHashTableServer;
026import edu.jas.util.DistThreadPool;
027import edu.jas.util.RemoteExecutable;
028import edu.jas.util.SocketChannel;
029import edu.jas.util.TaggedSocketChannel;
030import edu.jas.util.Terminator;
031import edu.jas.util.ThreadPool;
032
033
034/**
035 * Groebner Base distributed hybrid algorithm. Implements a distributed memory
036 * with multi-core CPUs parallel version of Groebner bases with executable
037 * channels. Using pairlist class, distributed multi-threaded tasks do
038 * reduction, one communication channel per remote node.
039 * @param <C> coefficient type
040 * @author Heinz Kredel
041 */
042
043public class GroebnerBaseDistributedHybridEC<C extends RingElem<C>> extends GroebnerBaseAbstract<C> {
044
045
046    private static final Logger logger = LogManager.getLogger(GroebnerBaseDistributedHybridEC.class);
047
048
049    private static final boolean debug = logger.isDebugEnabled();
050
051
052    /**
053     * Number of threads to use.
054     */
055    protected final int threads;
056
057
058    /**
059     * Default number of threads.
060     */
061    protected static final int DEFAULT_THREADS = 2;
062
063
064    /**
065     * Number of threads per node to use.
066     */
067    protected final int threadsPerNode;
068
069
070    /**
071     * Default number of threads per compute node.
072     */
073    protected static final int DEFAULT_THREADS_PER_NODE = 1;
074
075
076    /**
077     * Pool of threads to use.
078     */
079    //protected final ExecutorService pool; // not for single node tests
080    protected transient final ThreadPool pool;
081
082
083    /**
084     * Default server port.
085     */
086    protected static final int DEFAULT_PORT = 55711;
087
088
089    /**
090     * Default distributed hash table server port.
091     */
092    protected final int DHT_PORT;
093
094
095    /**
096     * machine file to use.
097     */
098    protected final String mfile;
099
100
101    /**
102     * Server port to use.
103     */
104    protected final int port;
105
106
107    /**
108     * Distributed thread pool to use.
109     */
110    private final transient DistThreadPool dtp;
111
112
113    /**
114     * Distributed hash table server to use.
115     */
116    private final transient DistHashTableServer<Integer> dhts;
117
118
119    /**
120     * Message tag for pairs.
121     */
122    public static final Integer pairTag = Integer.valueOf(1);
123
124
125    /**
126     * Message tag for results.
127     */
128    public static final Integer resultTag = Integer.valueOf(2);
129
130
131    /**
132     * Message tag for acknowledgments.
133     */
134    public static final Integer ackTag = Integer.valueOf(3);
135
136
137    /**
138     * Constructor.
139     * @param mfile name of the machine file.
140     */
141    public GroebnerBaseDistributedHybridEC(String mfile) {
142        this(mfile, DEFAULT_THREADS, DEFAULT_PORT);
143    }
144
145
146    /**
147     * Constructor.
148     * @param mfile name of the machine file.
149     * @param threads number of threads to use.
150     */
151    public GroebnerBaseDistributedHybridEC(String mfile, int threads) {
152        this(mfile, threads, new ThreadPool(threads), DEFAULT_PORT);
153    }
154
155
156    /**
157     * Constructor.
158     * @param mfile name of the machine file.
159     * @param threads number of threads to use.
160     * @param port server port to use.
161     */
162    public GroebnerBaseDistributedHybridEC(String mfile, int threads, int port) {
163        this(mfile, threads, new ThreadPool(threads), port);
164    }
165
166
167    /**
168     * Constructor.
169     * @param mfile name of the machine file.
170     * @param threads number of threads to use.
171     * @param threadsPerNode threads per node to use.
172     * @param port server port to use.
173     */
174    public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, int port) {
175        this(mfile, threads, threadsPerNode, new ThreadPool(threads), port);
176    }
177
178
179    /**
180     * Constructor.
181     * @param mfile name of the machine file.
182     * @param threads number of threads to use.
183     * @param pool ThreadPool to use.
184     * @param port server port to use.
185     */
186    public GroebnerBaseDistributedHybridEC(String mfile, int threads, ThreadPool pool, int port) {
187        this(mfile, threads, DEFAULT_THREADS_PER_NODE, pool, port);
188    }
189
190
191    /**
192     * Constructor.
193     * @param mfile name of the machine file.
194     * @param threads number of threads to use.
195     * @param threadsPerNode threads per node to use.
196     * @param pl pair selection strategy
197     * @param port server port to use.
198     */
199    public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, PairList<C> pl,
200                    int port) {
201        this(mfile, threads, threadsPerNode, new ThreadPool(threads), pl, port);
202    }
203
204
205    /**
206     * Constructor.
207     * @param mfile name of the machine file.
208     * @param threads number of threads to use.
209     * @param threadsPerNode threads per node to use.
210     * @param port server port to use.
211     */
212    public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, ThreadPool pool,
213                    int port) {
214        this(mfile, threads, threadsPerNode, pool, new OrderedPairlist<C>(), port);
215    }
216
217
218    /**
219     * Constructor.
220     * @param mfile name of the machine file.
221     * @param threads number of threads to use.
222     * @param threadsPerNode threads per node to use.
223     * @param pool ThreadPool to use.
224     * @param pl pair selection strategy
225     * @param port server port to use.
226     */
227    public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, ThreadPool pool,
228                    PairList<C> pl, int port) {
229        super(new ReductionPar<C>(), pl);
230        this.threads = threads;
231        if (mfile == null || mfile.length() == 0) {
232            this.mfile = "../util/machines"; // contains localhost
233        } else {
234            this.mfile = mfile;
235        }
236        if (threads < 1) {
237            threads = 1;
238        }
239        this.threadsPerNode = threadsPerNode;
240        if (pool == null) {
241            pool = new ThreadPool(threads);
242        }
243        this.pool = pool;
244        this.port = port;
245        logger.info("machine file " + mfile + ", port = " + port);
246        this.dtp = new DistThreadPool(this.threads, this.mfile);
247        logger.info("running " + dtp);
248        this.DHT_PORT = this.dtp.getEC().getMasterPort() + 100;
249        this.dhts = new DistHashTableServer<Integer>(this.DHT_PORT);
250        this.dhts.init();
251        logger.info("running " + dhts);
252    }
253
254
255    /**
256     * Cleanup and terminate ThreadPool.
257     */
258    @Override
259    public void terminate() {
260        terminate(true);
261    }
262
263
264    /**
265     * Terminates the distributed thread pools.
266     * @param shutDown true, if shut-down of the remote executable servers is
267     *            requested, false, if remote executable servers stay alive.
268     */
269    public void terminate(boolean shutDown) {
270        pool.terminate();
271        dtp.terminate(shutDown);
272        logger.info("dhts.terminate()");
273        dhts.terminate();
274    }
275
276
277    /**
278     * Distributed Groebner base.
279     * @param modv number of module variables.
280     * @param F polynomial list.
281     * @return GB(F) a Groebner base of F or null, if a IOException occurs.
282     */
283    public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) {
284        List<GenPolynomial<C>> Fp = normalizeZerosOnes(F);
285        Fp = PolyUtil.<C> monic(Fp);
286        if (Fp.size() <= 1) {
287            return Fp;
288        }
289        if (!Fp.get(0).ring.coFac.isField()) {
290            throw new IllegalArgumentException("coefficients not from a field");
291        }
292
293        String master = dtp.getEC().getMasterHost();
294        //int port = dtp.getEC().getMasterPort(); // wrong port
295        GBHybridExerClient<C> gbc = new GBHybridExerClient<C>(master, threadsPerNode, port, DHT_PORT);
296        for (int i = 0; i < threads; i++) {
297            // schedule remote clients
298            dtp.addJob(gbc);
299        }
300        // run master
301        List<GenPolynomial<C>> G = GBMaster(modv, Fp);
302        return G;
303    }
304
305
306    /**
307     * Distributed hybrid Groebner base.
308     * @param modv number of module variables.
309     * @param F non empty monic polynomial list without zeros.
310     * @return GB(F) a Groebner base of F or null, if a IOException occurs.
311     */
312    List<GenPolynomial<C>> GBMaster(int modv, List<GenPolynomial<C>> F) {
313        long t = System.currentTimeMillis();
314        ChannelFactory cf = new ChannelFactory(port);
315        cf.init();
316
317        List<GenPolynomial<C>> G = F;
318        if (G.isEmpty()) {
319            throw new IllegalArgumentException("empty polynomial list not allowed");
320        }
321        GenPolynomialRing<C> ring = G.get(0).ring;
322        PairList<C> pairlist = strategy.create(modv, ring);
323        pairlist.put(G);
324
325        /*
326        GenPolynomial<C> p;
327        List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>();
328        PairList<C> pairlist = null;
329        boolean oneInGB = false;
330        int l = F.size();
331        int unused;
332        ListIterator<GenPolynomial<C>> it = F.listIterator();
333        while (it.hasNext()) {
334            p = it.next();
335            if (p.length() > 0) {
336                p = p.monic();
337                if (p.isONE()) {
338                    oneInGB = true;
339                    G.clear();
340                    G.add(p);
341                    //return G; must signal termination to others
342                }
343                if (!oneInGB) {
344                    G.add(p);
345                }
346                if (pairlist == null) {
347                    //pairlist = new OrderedPairlist<C>(modv, p.ring);
348                    pairlist = strategy.create(modv, p.ring);
349                    if (!p.ring.coFac.isField()) {
350                        throw new IllegalArgumentException("coefficients not from a field");
351                    }
352                }
353                // theList not updated here
354                if (p.isONE()) {
355                    unused = pairlist.putOne();
356                } else {
357                    unused = pairlist.put(p);
358                }
359            } else {
360                l--;
361            }
362        }
363        //if (l <= 1) {
364        //return G; must signal termination to others
365        //}
366        */
367        logger.info("start " + pairlist);
368        DistHashTable<Integer, GenPolynomial<C>> theList = new DistHashTable<Integer, GenPolynomial<C>>(
369                        "localhost", DHT_PORT);
370        theList.init();
371        List<GenPolynomial<C>> al = pairlist.getList();
372        for (int i = 0; i < al.size(); i++) {
373            // no wait required
374            GenPolynomial<C> nn = theList.put(Integer.valueOf(i), al.get(i));
375            if (nn != null) {
376                logger.info("double polynomials " + i + ", nn = " + nn + ", al(i) = " + al.get(i));
377            }
378        }
379
380        Terminator finner = new Terminator(threads * threadsPerNode);
381        HybridReducerServerEC<C> R;
382        logger.info("using pool = " + pool);
383        for (int i = 0; i < threads; i++) {
384            R = new HybridReducerServerEC<C>(threadsPerNode, finner, cf, theList, pairlist);
385            pool.addJob(R);
386            //logger.info("server submitted " + R);
387        }
388        logger.info("main loop waiting " + finner);
389        finner.waitDone();
390        int ps = theList.size();
391        logger.info("#distributed list = " + ps);
392        // make sure all polynomials arrived: not needed in master
393        // G = (ArrayList)theList.values();
394        G = pairlist.getList();
395        if (ps != G.size()) {
396            logger.info("#distributed list = " + theList.size() + " #pairlist list = " + G.size());
397        }
398        for (GenPolynomial<C> q : theList.getValueList()) {
399            if (debug && q != null && !q.isZERO()) {
400                logger.debug("final q = " + q.leadingExpVector());
401            }
402        }
403        logger.debug("distributed list end");
404        long time = System.currentTimeMillis();
405        List<GenPolynomial<C>> Gp;
406        Gp = minimalGB(G); // not jet distributed but threaded
407        time = System.currentTimeMillis() - time;
408        logger.debug("parallel gbmi time = " + time);
409        G = Gp;
410        logger.debug("server cf.terminate()");
411        cf.terminate();
412        logger.debug("server theList.terminate() " + theList.size());
413        theList.clear();
414        theList.terminate();
415        t = System.currentTimeMillis() - t;
416        logger.info("server GB end, time = " + t + ", " + pairlist.toString());
417        return G;
418    }
419
420
421    /**
422     * GB distributed client part.
423     * @param host the server runs on.
424     * @param port the server runs.
425     * @param dhtport of the DHT server.
426     * @throws IOException
427     */
428    public static <C extends RingElem<C>> void clientPart(String host, int threadsPerNode, int port,
429                    int dhtport) throws IOException {
430        ChannelFactory cf = new ChannelFactory(port + 10); // != port for localhost
431        cf.init();
432        logger.info("clientPart connecting to " + host + ", port = " + port + ", dhtport = " + dhtport);
433        SocketChannel channel = cf.getChannel(host, port);
434        TaggedSocketChannel pairChannel = new TaggedSocketChannel(channel);
435        pairChannel.init();
436
437        DistHashTable<Integer, GenPolynomial<C>> theList = new DistHashTable<Integer, GenPolynomial<C>>(host,
438                        dhtport);
439        theList.init();
440
441        ThreadPool pool = new ThreadPool(threadsPerNode);
442        logger.info("client using pool = " + pool);
443        for (int i = 0; i < threadsPerNode; i++) {
444            HybridReducerClientEC<C> Rr = new HybridReducerClientEC<C>(/*threadsPerNode,*/pairChannel, /*i,*/
445            theList);
446            pool.addJob(Rr);
447        }
448        logger.debug("clients submitted");
449
450        pool.terminate();
451        logger.debug("client pool.terminate()");
452
453        pairChannel.close();
454        logger.debug("client pairChannel.close()");
455
456        //master only: theList.clear();
457        theList.terminate();
458        cf.terminate();
459        logger.info("client cf.terminate()");
460
461        channel.close();
462        logger.info("client channel.close()");
463        return;
464    }
465
466
467    /**
468     * Minimal ordered groebner basis.
469     * @param Fp a Groebner base.
470     * @return a reduced Groebner base of Fp.
471     */
472    @Override
473    public List<GenPolynomial<C>> minimalGB(List<GenPolynomial<C>> Fp) {
474        GenPolynomial<C> a;
475        ArrayList<GenPolynomial<C>> G;
476        G = new ArrayList<GenPolynomial<C>>(Fp.size());
477        ListIterator<GenPolynomial<C>> it = Fp.listIterator();
478        while (it.hasNext()) {
479            a = it.next();
480            if (a.length() != 0) { // always true
481                // already monic  a = a.monic();
482                G.add(a);
483            }
484        }
485        if (G.size() <= 1) {
486            return G;
487        }
488
489        ExpVector e;
490        ExpVector f;
491        GenPolynomial<C> p;
492        ArrayList<GenPolynomial<C>> F;
493        F = new ArrayList<GenPolynomial<C>>(G.size());
494        boolean mt;
495
496        while (G.size() > 0) {
497            a = G.remove(0);
498            e = a.leadingExpVector();
499
500            it = G.listIterator();
501            mt = false;
502            while (it.hasNext() && !mt) {
503                p = it.next();
504                f = p.leadingExpVector();
505                mt = e.multipleOf(f);
506            }
507            it = F.listIterator();
508            while (it.hasNext() && !mt) {
509                p = it.next();
510                f = p.leadingExpVector();
511                mt = e.multipleOf(f);
512            }
513            if (!mt) {
514                F.add(a);
515            } else {
516                // System.out.println("dropped " + a.length());
517            }
518        }
519        G = F;
520        if (G.size() <= 1) {
521            return G;
522        }
523        Collections.reverse(G); // important for lex GB
524
525        @SuppressWarnings("cast")
526        MiReducerServer<C>[] mirs = (MiReducerServer<C>[]) new MiReducerServer[G.size()];
527        int i = 0;
528        F = new ArrayList<GenPolynomial<C>>(G.size());
529        while (G.size() > 0) {
530            a = G.remove(0);
531            // System.out.println("doing " + a.length());
532            List<GenPolynomial<C>> R = new ArrayList<GenPolynomial<C>>(G.size() + F.size());
533            R.addAll(G);
534            R.addAll(F);
535            mirs[i] = new MiReducerServer<C>(R, a);
536            pool.addJob(mirs[i]);
537            i++;
538            F.add(a);
539        }
540        G = F;
541        F = new ArrayList<GenPolynomial<C>>(G.size());
542        for (i = 0; i < mirs.length; i++) {
543            a = mirs[i].getNF();
544            F.add(a);
545        }
546        return F;
547    }
548
549}
550
551
552/**
553 * Distributed server reducing worker proxy threads.
554 * @param <C> coefficient type
555 */
556class HybridReducerServerEC<C extends RingElem<C>> implements Runnable {
557
558
559    private static final Logger logger = LogManager.getLogger(HybridReducerServerEC.class);
560
561
562    private static final boolean debug = logger.isDebugEnabled();
563
564
565    private final Terminator finner;
566
567
568    private final ChannelFactory cf;
569
570
571    private TaggedSocketChannel pairChannel;
572
573
574    private final DistHashTable<Integer, GenPolynomial<C>> theList;
575
576
577    private final PairList<C> pairlist;
578
579
580    private final int threadsPerNode;
581
582
583    /**
584     * Message tag for pairs.
585     */
586    public final Integer pairTag = GroebnerBaseDistributedHybridEC.pairTag;
587
588
589    /**
590     * Message tag for results.
591     */
592    public final Integer resultTag = GroebnerBaseDistributedHybridEC.resultTag;
593
594
595    /**
596     * Message tag for acknowledgments.
597     */
598    public final Integer ackTag = GroebnerBaseDistributedHybridEC.ackTag;
599
600
601    /**
602     * Constructor.
603     * @param tpn number of threads per node
604     * @param fin terminator
605     * @param cf channel factory
606     * @param dl distributed hash table
607     * @param L ordered pair list
608     */
609    HybridReducerServerEC(int tpn, Terminator fin, ChannelFactory cf,
610                    DistHashTable<Integer, GenPolynomial<C>> dl, PairList<C> L) {
611        threadsPerNode = tpn;
612        finner = fin;
613        this.cf = cf;
614        theList = dl;
615        pairlist = L;
616        //logger.info("reducer server created " + this);
617    }
618
619
620    /**
621     * Work loop.
622     * @see java.lang.Runnable#run()
623     */
624    @Override
625    public void run() {
626        logger.info("reducer server running with " + cf);
627        SocketChannel channel = null;
628        try {
629            channel = cf.getChannel();
630            pairChannel = new TaggedSocketChannel(channel);
631            pairChannel.init();
632        } catch (InterruptedException e) {
633            logger.debug("get pair channel interrupted");
634            e.printStackTrace();
635            return;
636        }
637        if (debug) {
638            logger.info("pairChannel   = " + pairChannel);
639        }
640        // record idle remote workers (minus one?)
641        //finner.beIdle(threadsPerNode-1);
642        finner.initIdle(threadsPerNode);
643        AtomicInteger active = new AtomicInteger(0);
644
645        // start receiver
646        HybridReducerReceiverEC<C> receiver = new HybridReducerReceiverEC<C>(/*threadsPerNode,*/finner,
647                        active, pairChannel, theList, pairlist);
648        receiver.start();
649
650        Pair<C> pair;
651        //boolean set = false;
652        boolean goon = true;
653        //int polIndex = -1;
654        int red = 0;
655        int sleeps = 0;
656
657        // while more requests
658        while (goon) {
659            // receive request if thread is reported incactive
660            logger.debug("receive request");
661            Object req = null;
662            try {
663                req = pairChannel.receive(pairTag);
664            } catch (InterruptedException e) {
665                goon = false;
666                e.printStackTrace();
667            } catch (IOException e) {
668                goon = false;
669                e.printStackTrace();
670            } catch (ClassNotFoundException e) {
671                goon = false;
672                e.printStackTrace();
673            }
674            //logger.info("received request, req = " + req);
675            if (req == null) {
676                goon = false;
677                break;
678            }
679            if (!(req instanceof GBTransportMessReq)) {
680                goon = false;
681                break;
682            }
683
684            // find pair and manage termination status
685            logger.debug("find pair");
686            while (!pairlist.hasNext()) { // wait
687                if (!finner.hasJobs() && !pairlist.hasNext()) {
688                    goon = false;
689                    break;
690                }
691                try {
692                    sleeps++;
693                    if (sleeps % 3 == 0) {
694                        logger.info("waiting for reducers, remaining = " + finner);
695                    }
696                    Thread.sleep(100);
697                } catch (InterruptedException e) {
698                    goon = false;
699                    break;
700                }
701            }
702            if (Thread.currentThread().isInterrupted()) {
703                goon = false;
704                break;
705            }
706            if (!pairlist.hasNext() && !finner.hasJobs()) {
707                logger.info("termination detection: no pairs and no jobs left");
708                goon = false;
709                break; //continue; //break?
710            }
711            finner.notIdle(); // before pairlist get!!
712            pair = pairlist.removeNext();
713            // send pair to client, even if null
714            if (debug) {
715                logger.info("active count = " + active.get());
716                logger.info("send pair = " + pair);
717            }
718            GBTransportMess msg = null;
719            if (pair != null) {
720                msg = new GBTransportMessPairIndex(pair); //,pairlist.size()-1); // size-1
721            } else {
722                msg = new GBTransportMess(); // not End(); at this time
723                // goon ?= false;
724            }
725            try {
726                red++;
727                pairChannel.send(pairTag, msg);
728                @SuppressWarnings("unused")
729                int a = active.getAndIncrement();
730            } catch (IOException e) {
731                e.printStackTrace();
732                goon = false;
733                break;
734            }
735            //logger.debug("#distributed list = " + theList.size());
736        }
737        logger.info("terminated, send " + red + " reduction pairs");
738
739        /*
740         * send end mark to clients
741         */
742        logger.debug("send end");
743        try {
744            for (int i = 0; i < threadsPerNode; i++) { // -1
745                //do not wait: Object rq = pairChannel.receive(pairTag);
746                pairChannel.send(pairTag, new GBTransportMessEnd());
747            }
748            // send also end to receiver
749            pairChannel.send(resultTag, new GBTransportMessEnd());
750            //beware of race condition 
751        } catch (IOException e) {
752            if (logger.isDebugEnabled()) {
753                e.printStackTrace();
754            }
755        }
756        receiver.terminate();
757
758        int d = active.get();
759        if (d > 0) {
760            logger.info("remaining active tasks = " + d);
761        }
762        //logger.info("terminated, send " + red + " reduction pairs");
763        pairChannel.close();
764        logger.debug("redServ pairChannel.close()");
765        finner.release();
766
767        channel.close();
768        logger.info("redServ channel.close()");
769    }
770}
771
772
773/**
774 * Distributed server receiving worker thread.
775 * @param <C> coefficient type
776 */
777class HybridReducerReceiverEC<C extends RingElem<C>> extends Thread {
778
779
780    private static final Logger logger = LogManager.getLogger(HybridReducerReceiverEC.class);
781
782
783    private static final boolean debug = logger.isDebugEnabled();
784
785
786    private final DistHashTable<Integer, GenPolynomial<C>> theList;
787
788
789    private final PairList<C> pairlist;
790
791
792    private final TaggedSocketChannel pairChannel;
793
794
795    private final Terminator finner;
796
797
798    //private final int threadsPerNode;
799
800
801    private final AtomicInteger active;
802
803
804    private volatile boolean goon;
805
806
807    /**
808     * Message tag for pairs.
809     */
810    public final Integer pairTag = GroebnerBaseDistributedHybridEC.pairTag;
811
812
813    /**
814     * Message tag for results.
815     */
816    public final Integer resultTag = GroebnerBaseDistributedHybridEC.resultTag;
817
818
819    /**
820     * Message tag for acknowledgments.
821     */
822    public final Integer ackTag = GroebnerBaseDistributedHybridEC.ackTag;
823
824
825    /**
826     * Constructor.
827     * @param fin terminator
828     * @param a active remote tasks count
829     * @param pc tagged socket channel
830     * @param dl distributed hash table
831     * @param L ordered pair list
832     */
833    //param tpn number of threads per node
834    HybridReducerReceiverEC(/*int tpn,*/Terminator fin, AtomicInteger a, TaggedSocketChannel pc,
835                    DistHashTable<Integer, GenPolynomial<C>> dl, PairList<C> L) {
836        active = a;
837        //threadsPerNode = tpn;
838        finner = fin;
839        pairChannel = pc;
840        theList = dl;
841        pairlist = L;
842        goon = true;
843        //logger.info("reducer server created " + this);
844    }
845
846
847    /**
848     * Work loop.
849     * @see java.lang.Thread#run()
850     */
851    @Override
852    public void run() {
853        //Pair<C> pair = null;
854        GenPolynomial<C> H = null;
855        int red = 0;
856        int polIndex = -1;
857        //Integer senderId; // obsolete
858
859        // while more requests
860        while (goon) {
861            // receive request
862            logger.debug("receive result");
863            //senderId = null;
864            Object rh = null;
865            try {
866                rh = pairChannel.receive(resultTag);
867                @SuppressWarnings("unused")
868                int i = active.getAndDecrement();
869            } catch (InterruptedException e) {
870                goon = false;
871                //e.printStackTrace();
872                //?? finner.initIdle(1);
873                break;
874            } catch (IOException e) {
875                e.printStackTrace();
876                goon = false;
877                finner.initIdle(1);
878                break;
879            } catch (ClassNotFoundException e) {
880                e.printStackTrace();
881                goon = false;
882                finner.initIdle(1);
883                break;
884            }
885            logger.info("received H polynomial");
886            if (rh == null) {
887                if (this.isInterrupted()) {
888                    goon = false;
889                    finner.initIdle(1);
890                    break;
891                }
892                //finner.initIdle(1);
893            } else if (rh instanceof GBTransportMessEnd) { // should only happen from server
894                logger.info("received GBTransportMessEnd");
895                goon = false;
896                //?? finner.initIdle(1);
897                break;
898            } else if (rh instanceof GBTransportMessPoly) {
899                // update pair list
900                red++;
901                GBTransportMessPoly<C> mpi = (GBTransportMessPoly<C>) rh;
902                H = mpi.pol;
903                //senderId = mpi.threadId;
904                if (H != null) {
905                    if (debug) {
906                        logger.info("H = " + H.leadingExpVector());
907                    }
908                    if (!H.isZERO()) {
909                        if (H.isONE()) {
910                            // finner.allIdle();
911                            polIndex = pairlist.putOne();
912                            theList.putWait(Integer.valueOf(polIndex), H);
913                            //goon = false; must wait for other clients
914                            //finner.initIdle(1);
915                            //break;
916                        } else {
917                            polIndex = pairlist.put(H);
918                            // use putWait ? but still not all distributed
919                            //GenPolynomial<C> nn = 
920                            theList.putWait(Integer.valueOf(polIndex), H);
921                        }
922                    }
923                }
924            }
925            // only after recording in pairlist !
926            finner.initIdle(1);
927            try {
928                pairChannel.send(ackTag, new GBTransportMess());
929                logger.debug("send acknowledgement");
930            } catch (IOException e) {
931                e.printStackTrace();
932                goon = false;
933                break;
934            }
935        } // end while
936        goon = false;
937        logger.info("terminated, received " + red + " reductions");
938    }
939
940
941    /**
942     * Terminate.
943     */
944    public void terminate() {
945        goon = false;
946        //this.interrupt();
947        try {
948            this.join();
949        } catch (InterruptedException e) {
950            // unfug Thread.currentThread().interrupt();
951        }
952        logger.debug("HybridReducerReceiver terminated");
953    }
954
955}
956
957
958/**
959 * Distributed clients reducing worker threads.
960 */
961class HybridReducerClientEC<C extends RingElem<C>> implements Runnable {
962
963
964    private static final Logger logger = LogManager.getLogger(HybridReducerClientEC.class);
965
966
967    private static final boolean debug = logger.isDebugEnabled();
968
969
970    private final TaggedSocketChannel pairChannel;
971
972
973    private final DistHashTable<Integer, GenPolynomial<C>> theList;
974
975
976    private final ReductionPar<C> red;
977
978
979    //private final int threadsPerNode;
980
981
982    /*
983     * Identification number for this thread.
984     */
985    //public final Integer threadId; // obsolete
986
987
988    /**
989     * Message tag for pairs.
990     */
991    public final Integer pairTag = GroebnerBaseDistributedHybridEC.pairTag;
992
993
994    /**
995     * Message tag for results.
996     */
997    public final Integer resultTag = GroebnerBaseDistributedHybridEC.resultTag;
998
999
1000    /**
1001     * Message tag for acknowledgments.
1002     */
1003    public final Integer ackTag = GroebnerBaseDistributedHybridEC.ackTag;
1004
1005
1006    /**
1007     * Constructor.
1008     * @param tc tagged socket channel
1009     * @param dl distributed hash table
1010     */
1011    //param tpn number of threads per node
1012    //param tid thread identification
1013    HybridReducerClientEC(/*int tpn,*/TaggedSocketChannel tc, /*Integer tid,*/
1014                    DistHashTable<Integer, GenPolynomial<C>> dl) {
1015        //threadsPerNode = tpn;
1016        pairChannel = tc;
1017        //threadId = 100 + tid; // keep distinct from other tags
1018        theList = dl;
1019        red = new ReductionPar<C>();
1020    }
1021
1022
1023    /**
1024     * Work loop.
1025     * @see java.lang.Runnable#run()
1026     */
1027    @Override
1028    public void run() {
1029        if (debug) {
1030            logger.info("pairChannel   = " + pairChannel + " reducer client running");
1031        }
1032        Pair<C> pair = null;
1033        GenPolynomial<C> pi, pj, ps;
1034        GenPolynomial<C> S;
1035        GenPolynomial<C> H = null;
1036        //boolean set = false;
1037        boolean goon = true;
1038        boolean doEnd = true;
1039        int reduction = 0;
1040        //int sleeps = 0;
1041        Integer pix, pjx, psx;
1042
1043        while (goon) {
1044            /* protocol:
1045             * request pair, process pair, send result, receive acknowledgment
1046             */
1047            // pair = (Pair) pairlist.removeNext();
1048            Object req = new GBTransportMessReq();
1049            logger.debug("send request");
1050            try {
1051                pairChannel.send(pairTag, req);
1052            } catch (IOException e) {
1053                goon = false;
1054                if (logger.isDebugEnabled()) {
1055                    e.printStackTrace();
1056                }
1057                logger.info("receive pair, IOexception ");
1058                break;
1059            }
1060            logger.debug("receive pair, goon = " + goon);
1061            doEnd = true;
1062            Object pp = null;
1063            try {
1064                pp = pairChannel.receive(pairTag);
1065            } catch (InterruptedException e) {
1066                goon = false;
1067                e.printStackTrace();
1068            } catch (IOException e) {
1069                goon = false;
1070                if (logger.isDebugEnabled()) {
1071                    e.printStackTrace();
1072                }
1073                break;
1074            } catch (ClassNotFoundException e) {
1075                goon = false;
1076                e.printStackTrace();
1077            }
1078            if (debug) {
1079                logger.info("received pair = " + pp);
1080            }
1081            H = null;
1082            if (pp == null) { // should not happen
1083                continue;
1084            }
1085            if (pp instanceof GBTransportMessEnd) {
1086                goon = false;
1087                //doEnd = false;
1088                continue;
1089            }
1090            if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) {
1091                pi = pj = ps = null;
1092                if (pp instanceof GBTransportMessPair) { // obsolet, for tests
1093                    GBTransportMessPair<C> tmp = (GBTransportMessPair<C>) pp;
1094                    pair = tmp.pair;
1095                    if (pair != null) {
1096                        pi = pair.pi;
1097                        pj = pair.pj;
1098                        //logger.debug("pair: pix = " + pair.i 
1099                        //               + ", pjx = " + pair.j);
1100                    }
1101                }
1102                if (pp instanceof GBTransportMessPairIndex) {
1103                    GBTransportMessPairIndex tmpi = (GBTransportMessPairIndex) pp;
1104                    pix = tmpi.i;
1105                    pjx = tmpi.j;
1106                    psx = tmpi.s;
1107                    pi = theList.getWait(pix);
1108                    pj = theList.getWait(pjx);
1109                    ps = theList.getWait(psx);
1110                    //logger.info("pix = " + pix + ", pjx = " + pjx + ", psx = " + psx);
1111                }
1112                if (pi != null && pj != null) {
1113                    S = red.SPolynomial(pi, pj);
1114                    //logger.info("ht(S) = " + S.leadingExpVector());
1115                    if (S.isZERO()) {
1116                        // pair.setZero(); does not work in dist
1117                    } else {
1118                        if (logger.isDebugEnabled()) {
1119                            logger.debug("ht(S) = " + S.leadingExpVector());
1120                        }
1121                        H = red.normalform(theList, S);
1122                        //logger.info("ht(H) = " + H.leadingExpVector());
1123                        reduction++;
1124                        if (H.isZERO()) {
1125                            // pair.setZero(); does not work in dist
1126                        } else {
1127                            H = H.monic();
1128                            if (logger.isInfoEnabled()) {
1129                                logger.info("ht(H) = " + H.leadingExpVector());
1130                            }
1131                        }
1132                    }
1133                } else {
1134                    logger.info("pi = " + pi + ", pj = " + pj + ", ps = " + ps);
1135                }
1136            }
1137            if (pp instanceof GBTransportMess) {
1138                logger.debug("null pair results in null H poly");
1139            }
1140
1141            // send H or must send null, if not at end
1142            if (logger.isDebugEnabled()) {
1143                logger.debug("#distributed list = " + theList.size());
1144                logger.debug("send H polynomial = " + H);
1145            }
1146            try {
1147                pairChannel.send(resultTag, new GBTransportMessPoly<C>(H)); //,threadId));
1148                doEnd = false;
1149            } catch (IOException e) {
1150                goon = false;
1151                e.printStackTrace();
1152            }
1153            //logger.info("done send poly message of " + pp);
1154            try {
1155                //pp = pairChannel.receive(threadId);
1156                pp = pairChannel.receive(ackTag);
1157            } catch (InterruptedException e) {
1158                goon = false;
1159                e.printStackTrace();
1160            } catch (IOException e) {
1161                goon = false;
1162                if (logger.isDebugEnabled()) {
1163                    e.printStackTrace();
1164                }
1165                break;
1166            } catch (ClassNotFoundException e) {
1167                goon = false;
1168                e.printStackTrace();
1169            }
1170            if (!(pp instanceof GBTransportMess)) {
1171                logger.error("invalid acknowledgement " + pp);
1172            }
1173            logger.info("received acknowledgment ");
1174        }
1175        logger.info("terminated, " + reduction + " reductions, " + theList.size() + " polynomials");
1176        if (doEnd) {
1177            try {
1178                pairChannel.send(resultTag, new GBTransportMessEnd());
1179            } catch (IOException e) {
1180                //e.printStackTrace();
1181            }
1182            logger.debug("terminated, send done");
1183        }
1184    }
1185}
1186
1187
1188/**
1189 * Objects of this class are to be send to a ExecutableServer.
1190 */
1191class GBHybridExerClient<C extends RingElem<C>> implements RemoteExecutable {
1192
1193
1194    String host;
1195
1196
1197    int port;
1198
1199
1200    int dhtport;
1201
1202
1203    int threadsPerNode;
1204
1205
1206    /**
1207     * GBHybridExerClient.
1208     * @param host
1209     * @param port
1210     * @param dhtport
1211     */
1212    public GBHybridExerClient(String host, int threadsPerNode, int port, int dhtport) {
1213        this.host = host;
1214        this.threadsPerNode = threadsPerNode;
1215        this.port = port;
1216        this.dhtport = dhtport;
1217    }
1218
1219
1220    /**
1221     * run.
1222     */
1223    public void run() {
1224        try {
1225            GroebnerBaseDistributedHybridEC.<C> clientPart(host, threadsPerNode, port, dhtport);
1226        } catch (Exception e) {
1227            e.printStackTrace();
1228        }
1229    }
1230
1231
1232    /**
1233     * String representation.
1234     */
1235    @Override
1236    public String toString() {
1237        StringBuffer s = new StringBuffer("GBHybridExerClient(");
1238        s.append("host=" + host);
1239        s.append(", threadsPerNode=" + threadsPerNode);
1240        s.append(", port=" + port);
1241        s.append(", dhtport=" + dhtport);
1242        s.append(")");
1243        return s.toString();
1244    }
1245
1246}