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