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