001/*
002 * $Id$
003 */
004
005package edu.jas.gb;
006
007import java.util.ArrayList;
008import java.util.BitSet;
009import java.util.Comparator;
010import java.util.Iterator;
011import java.util.List;
012import java.util.SortedSet;
013import java.util.TreeSet;
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.GenSolvablePolynomialRing;
022import edu.jas.structure.RingElem;
023
024/**
025 * Critical pair list management.
026 * Makes some effort to produce the same sequence of critical pairs 
027 * as in the sequential case, when used in parallel.
028 * However already reduced pairs are not re-reduced if new
029 * polynomials appear.
030 * Implemented using GenPolynomial, SortedSet / TreeSet and BitSet.
031 * @author Heinz Kredel
032 */
033
034public class CriticalPairList<C extends RingElem<C>> extends OrderedPairlist<C> {
035
036    protected final SortedSet< CriticalPair<C> > pairlist; // hide super
037
038    protected int recordCount;
039
040    private static final Logger logger = LogManager.getLogger(CriticalPairList.class);
041
042
043    /**
044     * Constructor for CriticalPairList.
045     */
046    public CriticalPairList() {
047        super();
048        pairlist = null;
049    }
050
051
052    /**
053     * Constructor for CriticalPairList.
054     * @param r polynomial factory.
055     */
056    public CriticalPairList(GenPolynomialRing<C> r) {
057        this(0,r);
058    }
059
060
061    /**
062     * Constructor for CriticalPairList.
063     * @param m number of module variables.
064     * @param r polynomial factory.
065     */
066    public CriticalPairList(int m, GenPolynomialRing<C> r) {
067        super(m,r);
068        Comparator< AbstractPair<C> > cpc; 
069        cpc = new CriticalPairComparator<C>( ring.tord ); 
070        pairlist = new TreeSet< CriticalPair<C> >( cpc );
071        recordCount = 0;
072    }
073
074
075    /**
076     * Create a new PairList.
077     * @param r polynomial ring.
078     */
079    public PairList<C> create(GenPolynomialRing<C> r) {
080        return new CriticalPairList<C>(r);
081    }
082
083
084    /**
085     * Create a new PairList.
086     * @param m number of module variables.
087     * @param r polynomial ring.
088     */
089    public PairList<C> create(int m, GenPolynomialRing<C> r) {
090        return new CriticalPairList<C>(m,r);
091    }
092
093
094    /**
095     * Put a polynomial to the pairlist and reduction matrix.
096     * @param p polynomial.
097     * @return the index of the added polynomial.
098     */
099    public synchronized int put(GenPolynomial<C> p) { 
100        putCount++;
101        if ( oneInGB ) { 
102           return P.size()-1;
103        }
104        ExpVector e = p.leadingExpVector(); 
105        int len = P.size();
106        for ( int j = 0; j < len; j++ ) {
107            GenPolynomial<C> pj = P.get(j);
108            ExpVector f = pj.leadingExpVector(); 
109            if ( moduleVars > 0 ) { // test moduleCriterion
110               if ( !reduction.moduleCriterion( moduleVars, e, f) ) {
111                  continue; // skip pair
112               }
113            }
114            ExpVector g =  e.lcm( f );
115            CriticalPair<C> pair = new CriticalPair<C>( g, pj, p, j, len );
116            //System.out.println("put pair = " + pair );
117            pairlist.add( pair );
118        }
119        P.add( p );
120        BitSet redi = new BitSet();
121        redi.set( 0, len ); // >= jdk 1.4
122        red.add( redi );
123        if ( recordCount < len ) {
124            recordCount = len;
125        }
126        return len;
127    }
128
129
130    /**
131     * Test if there is possibly a pair in the list.
132     * @return true if a next pair could exist, otherwise false.
133     */
134    public synchronized boolean hasNext() { 
135          return pairlist.size() > 0;
136    }
137
138
139    /**
140     * Get and remove the next required pair from the pairlist.
141     * Apply the criterions 3 and 4 to see if the S-polynomial is required.
142     * The pair is not removed from the pair list.
143     * @return the next pair if one exists, otherwise null.
144     */
145    public synchronized Pair<C> removeNext() { 
146        CriticalPair<C> cp = getNext();
147        if ( cp == null ) {
148            return null;
149        }
150        return new Pair<C>(cp.pi,cp.pj,cp.i,cp.j);
151    }
152
153
154    /**
155     * Get the next required pair from the pairlist.
156     * Apply the criterions 3 and 4 to see if the S-polynomial is required.
157     * The pair is not removed from the pair list.
158     * @return the next pair if one exists, otherwise null.
159     */
160    public synchronized CriticalPair<C> getNext() { 
161        if ( oneInGB ) {
162           return null;
163        }
164        CriticalPair<C> pair = null;
165        Iterator< CriticalPair<C> > ip = pairlist.iterator();
166        boolean c = false;
167        while ( !c && ip.hasNext() )  { // findbugs
168           pair = ip.next();
169           if ( pair.getInReduction() ) {
170               continue;
171           }
172           if ( pair.getReductum() != null ) {
173               continue;
174           }
175           if ( logger.isInfoEnabled() ) {
176              logger.info("{}", pair);
177           }
178           if ( useCriterion4 ) {
179              c = reduction.criterion4( pair.pi, pair.pj, pair.e ); 
180              // System.out.println("c4  = " + c); 
181           } else {
182              c = true;
183           }
184           if ( c ) {
185              c = criterion3( pair.i, pair.j, pair.e );
186              // System.out.println("c3  = " + c); 
187           }
188           red.get( pair.j ).clear( pair.i ); // set(i,false) jdk1.4
189           if ( ! c ) { // set done
190               pair.setReductum( ring.getZERO() );
191           }
192        }
193        if ( ! c ) {
194           pair = null;
195        } else {
196           remCount++; // count only real pairs
197           pair.setInReduction(); // set to work
198        }
199        return pair; 
200    }
201
202
203    /**
204     * Record reduced polynomial.
205     * @param pair the corresponding critical pair.
206     * @param p polynomial.
207     * @return index of recorded polynomial, or -1 if not added.
208     */
209    public int record(CriticalPair<C> pair, GenPolynomial<C> p) { 
210        if ( p == null ) {
211            p = ring.getZERO();
212        }
213        pair.setReductum(p);
214        // trigger thread
215        if ( ! p.isZERO() && ! p.isONE() ) {
216           recordCount++;
217           return recordCount;
218        }
219        return -1;
220    }
221
222
223    /**
224     * Record reduced polynomial and update critical pair list. 
225     * Note: it is better to use record and uptate separately.
226     * @param pair the corresponding critical pair.
227     * @param p polynomial.
228     * @return index of recorded polynomial
229     */
230    public int update(CriticalPair<C> pair, GenPolynomial<C> p) { 
231        if ( p == null ) {
232            p = ring.getZERO();
233        }
234        pair.setReductum(p);
235        if ( ! p.isZERO() && ! p.isONE() ) {
236           recordCount++;
237        }
238        int c = update();
239        if (c < 0) { // use for findbugs 
240            System.out.println("c < 0");
241        }
242        if ( ! p.isZERO() && ! p.isONE() ) {
243           return recordCount;
244        } 
245        return -1;
246    }
247
248
249    /**
250     * Update pairlist.
251     * Preserve the sequential pair sequence.
252     * Remove pairs with completed reductions.
253     * @return the number of added polynomials.
254     */
255    public synchronized int update() { 
256        int num = 0;
257        if ( oneInGB ) {
258           return num;
259        }
260        while ( pairlist.size() > 0 ) {
261            CriticalPair<C> pair = pairlist.first();
262            GenPolynomial<C> p = pair.getReductum();
263            if ( p != null ) {
264               pairlist.remove( pair );
265               num++;
266               if ( ! p.isZERO() ) {
267                  if ( p.isONE() ) {
268                     putOne(); // sets size = 1
269                  } else {
270                     put( p ); // changes pair list
271                  }
272               }
273            } else {
274               break;
275            }
276        }
277        return num;
278    }
279
280
281    /**
282     * In work pairs. List pairs which are currently reduced.
283     * @return list of critical pairs which are in reduction.
284     */
285    public synchronized List<CriticalPair<C>> inWork() { 
286        List<CriticalPair<C>> iw;
287        iw = new ArrayList<CriticalPair<C>>();
288        if ( oneInGB ) {
289            return iw;
290        }
291        for ( CriticalPair<C> pair : pairlist ) {
292            if ( pair.getInReduction() ) {
293               iw.add( pair );
294            }
295        }
296        return iw;
297    }
298
299
300    /**
301     * Update pairlist, several pairs at once. 
302     * This version does not preserve the sequential pair sequence.
303     * Remove pairs with completed reductions.
304     * @return the number of added polynomials.
305     */
306    public synchronized int updateMany() { 
307        int num = 0;
308        if ( oneInGB ) {
309           return num;
310        }
311        List<CriticalPair<C>> rem = new ArrayList<CriticalPair<C>>();
312        for ( CriticalPair<C> pair : pairlist ) {
313            if ( pair.getReductum() != null ) {
314               rem.add( pair );
315               num++;
316            } else {
317               break;
318            }
319        }
320        // must work on a copy to avoid concurrent modification
321        for ( CriticalPair<C> pair : rem ) {
322            // System.out.println("update = " + pair); 
323            pairlist.remove( pair );
324            GenPolynomial<C> p = pair.getReductum();
325            if ( ! p.isZERO() ) {
326               if ( p.isONE() ) {
327                  putOne();
328               } else {
329                  put( p );
330               }
331            }
332        }
333        return num;
334    }
335
336
337    /**
338     * Put the ONE-Polynomial to the pairlist.
339     * @return the index of the last polynomial.
340     */
341    public synchronized int putOne() { 
342        super.putOne();
343        pairlist.clear();
344        return 0;
345    }
346
347}