001/*
002 * $Id$
003 */
004
005package edu.jas.gb;
006
007
008import java.util.ArrayList;
009import java.util.BitSet;
010import java.util.Iterator;
011import java.util.LinkedList;
012import java.util.List;
013import java.util.Map;
014import java.util.SortedMap;
015import java.util.TreeMap;
016
017import org.apache.logging.log4j.LogManager;
018import org.apache.logging.log4j.Logger;
019
020import edu.jas.poly.ExpVector;
021import edu.jas.poly.GenPolynomial;
022import edu.jas.poly.GenPolynomialRing;
023import edu.jas.structure.RingElem;
024
025
026/**
027 * Pair list management. For the Buchberger algorithm following the syzygy
028 * criterions by Gebauer & Möller. Implemented using GenPolynomial,
029 * TreeMap and BitSet.
030 * @author Heinz Kredel
031 */
032
033public class OrderedSyzPairlist<C extends RingElem<C>> extends OrderedPairlist<C> {
034
035
036    private static final Logger logger = LogManager.getLogger(OrderedSyzPairlist.class);
037
038
039    /**
040     * Constructor.
041     */
042    public OrderedSyzPairlist() {
043        super();
044    }
045
046
047    /**
048     * Constructor.
049     * @param r polynomial factory.
050     */
051    public OrderedSyzPairlist(GenPolynomialRing<C> r) {
052        this(0, r);
053    }
054
055
056    /**
057     * Constructor.
058     * @param m number of module variables.
059     * @param r polynomial factory.
060     */
061    public OrderedSyzPairlist(int m, GenPolynomialRing<C> r) {
062        super(m, r);
063    }
064
065
066    /**
067     * Create a new PairList.
068     * @param r polynomial ring.
069     */
070    @Override
071    public PairList<C> create(GenPolynomialRing<C> r) {
072        return new OrderedSyzPairlist<C>(r);
073    }
074
075
076    /**
077     * Create a new PairList.
078     * @param m number of module variables.
079     * @param r polynomial ring.
080     */
081    @Override
082    public PairList<C> create(int m, GenPolynomialRing<C> r) {
083        return new OrderedSyzPairlist<C>(m, r);
084    }
085
086
087    /**
088     * Put one Polynomial to the pairlist and reduction matrix. Removes all
089     * unnecessary pairs identified by the syzygy criterion and criterion 4.
090     * @param p polynomial.
091     * @return the index of the added polynomial.
092     */
093    @Override
094    public synchronized int put(GenPolynomial<C> p) {
095        putCount++;
096        if (oneInGB) {
097            return P.size() - 1;
098        }
099        ExpVector e = p.leadingExpVector();
100        int ps = P.size();
101        BitSet redi = new BitSet(); // all zeros
102        //redi.set( 0, ps ); // [0..ps-1] = true, i.e. all ones
103        red.add(redi);
104        P.add(p);
105        // remove from existing pairs:
106        List<ExpVector> es = new ArrayList<ExpVector>();
107        for (Map.Entry<ExpVector, LinkedList<Pair<C>>> me : pairlist.entrySet()) {
108            ExpVector g = me.getKey();
109            if (moduleVars > 0) {
110                if (!reduction.moduleCriterion(moduleVars, e, g)) {
111                    continue; // skip pair
112                }
113            }
114            ExpVector ge = g.lcm(e);
115            LinkedList<Pair<C>> ll = me.getValue();
116            if (g.compareTo(ge) == 0) {
117                LinkedList<Pair<C>> lle = new LinkedList<Pair<C>>();
118                for (Pair<C> pair : ll) {
119                    ExpVector eil = pair.pi.leadingExpVector().lcm(e);
120                    if (g.compareTo(eil) == 0) {
121                        continue;
122                    }
123                    ExpVector ejl = pair.pj.leadingExpVector().lcm(e);
124                    if (g.compareTo(ejl) == 0) {
125                        continue;
126                    }
127                    // g == ge && g != eil && g != ejl  
128                    red.get(pair.j).clear(pair.i);
129                    lle.add(pair);
130                }
131                if (lle.size() > 0) {
132                    for (Pair<C> pair : lle) {
133                        ll.remove(pair);
134                    }
135                    if (!es.contains(g)) {
136                        es.add(g);
137                    }
138                }
139            }
140        }
141        for (ExpVector ei : es) {
142            LinkedList<Pair<C>> ll = pairlist.get(ei);
143            if (ll != null && ll.size() == 0) {
144                ll = pairlist.remove(ei);
145            }
146        }
147        // generate new pairs:
148        SortedMap<ExpVector, LinkedList<Pair<C>>> npl = new TreeMap<ExpVector, LinkedList<Pair<C>>>(
149                        ring.tord.getAscendComparator());
150        for (int j = 0; j < ps; j++) {
151            GenPolynomial<C> pj = P.get(j);
152            ExpVector f = pj.leadingExpVector();
153            if (moduleVars > 0) {
154                if (!reduction.moduleCriterion(moduleVars, e, f)) {
155                    //red.get(j).clear(l); 
156                    continue; // skip pair
157                }
158            }
159            ExpVector g = e.lcm(f);
160            Pair<C> pair = new Pair<C>(pj, p, j, ps);
161            //System.out.println("pair.new      = " + pair);
162            //multiple pairs under same keys -> list of pairs
163            LinkedList<Pair<C>> xl = npl.get(g);
164            if (xl == null) {
165                xl = new LinkedList<Pair<C>>();
166            }
167            //xl.addLast( pair ); // first or last ?
168            xl.addFirst(pair); // first or last ? better for d- e-GBs
169            npl.put(g, xl);
170        }
171        //System.out.println("npl.new      = " + npl.keySet());
172        // skip by divisibility:
173        es = new ArrayList<ExpVector>(npl.size());
174        for (ExpVector eil : npl.keySet()) {
175            for (ExpVector ejl : npl.keySet()) {
176                if (eil.compareTo(ejl) == 0) {
177                    continue;
178                }
179                if (eil.multipleOf(ejl)) {
180                    if (!es.contains(eil)) {
181                        es.add(eil);
182                    }
183                }
184            }
185        }
186        //System.out.println("npl.skip div = " + es);
187        for (ExpVector ei : es) {
188            @SuppressWarnings("unused")
189            LinkedList<Pair<C>> ignored = npl.remove(ei);
190        }
191        // skip by criterion 4:
192        if (useCriterion4) {
193            es = new ArrayList<ExpVector>(npl.size());
194            for (Map.Entry<ExpVector, LinkedList<Pair<C>>> me : npl.entrySet()) {
195                ExpVector ei = me.getKey();
196                LinkedList<Pair<C>> exl = me.getValue(); //npl.get( ei );
197                //System.out.println("exl = " + exl ); 
198                boolean c = true;
199                for (Pair<C> pair : exl) {
200                    c = c && reduction.criterion4(pair.pi, pair.pj, pair.e);
201                }
202                if (c) {
203                    if (exl.size() > 1) {
204                        Pair<C> pair = exl.getFirst(); // or exl.getLast();
205                        exl.clear();
206                        exl.add(pair);
207                        //npl.put(ei,exl);
208                    }
209                } else {
210                    if (!es.contains(ei)) {
211                        es.add(ei);
212                    }
213                }
214            }
215            //System.out.println("npl.skip c4  = " + es);
216            for (ExpVector ei : es) {
217                @SuppressWarnings("unused")
218                LinkedList<Pair<C>> ignored = npl.remove(ei);
219            }
220        }
221        // add to existing pairlist:
222        //System.out.println("npl.put new  = " + npl.keySet() );  
223        for (Map.Entry<ExpVector, LinkedList<Pair<C>>> me : npl.entrySet()) {
224            ExpVector ei = me.getKey();
225            LinkedList<Pair<C>> exl = me.getValue(); //npl.get( ei );
226            for (Pair<C> pair : exl) {
227                red.get(pair.j).set(pair.i);
228            }
229            LinkedList<Pair<C>> ex = pairlist.get(ei); // wrong in findbugs
230            if (ex != null) {
231                exl.addAll(ex); // add new pairs first 
232                ex = exl;
233                //ex.addAll(exl); // add old pairs first
234            } else {
235                ex = exl;
236            }
237            pairlist.put(ei, ex); // replace ex
238        }
239        return P.size() - 1;
240    }
241
242
243    /**
244     * Remove the next required pair from the pairlist and reduction matrix.
245     * Apply the criterions 3 and 4 to see if the S-polynomial is required.
246     * @return the next pair if one exists, otherwise null.
247     */
248    @Override
249    public synchronized Pair<C> removeNext() {
250        if (oneInGB) {
251            return null;
252        }
253        Iterator<Map.Entry<ExpVector, LinkedList<Pair<C>>>> ip = pairlist.entrySet().iterator();
254        Pair<C> pair = null;
255        //boolean c = false;
256        int i, j;
257        while (ip.hasNext()) {
258            Map.Entry<ExpVector, LinkedList<Pair<C>>> me = ip.next();
259            ExpVector g = me.getKey();
260            LinkedList<Pair<C>> xl = me.getValue();
261            if (logger.isInfoEnabled())
262                logger.info("g  = {}", g);
263            pair = null;
264            while (xl.size() > 0) {
265                pair = xl.removeFirst(); // xl is also modified in pairlist 
266                i = pair.i;
267                j = pair.j;
268                //System.out.println("pair.remove = " + pair );
269                if (!red.get(j).get(i)) { // should not happen
270                    logger.warn("c_red.get({}).get({}) = {}", j, i, g);
271                    pair = null;
272                    continue;
273                }
274                red.get(j).clear(i);
275                break;
276            }
277            if (xl.size() == 0) {
278                ip.remove(); // = pairlist.remove( g );
279            }
280            if (pair != null) {
281                break;
282            }
283        }
284        if (pair != null) {
285            pair.maxIndex(P.size() - 1);
286            remCount++; // count only real pairs
287            if (logger.isDebugEnabled()) {
288                logger.info("pair({},{})", pair.j, pair.i);
289            }
290        }
291        return pair;
292    }
293
294
295    /**
296     * GB criterium 3.
297     * @return true if the S-polynomial(i,j) is required.
298     */
299    @Override
300    public boolean criterion3(int i, int j, ExpVector eij) {
301        throw new UnsupportedOperationException("not used in " + this.getClass().getName());
302    }
303
304}