001/*
002 * $Id$
003 */
004
005package edu.jas.gb;
006
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.ListIterator;
011
012import org.apache.logging.log4j.Logger;
013import org.apache.logging.log4j.LogManager; 
014
015import edu.jas.poly.GenPolynomial;
016import edu.jas.poly.GenPolynomialRing;
017import edu.jas.structure.RingElem;
018
019
020/**
021 * Groebner Base sequential algorithm. Implements Groebner bases and GB test.
022 * Uses sequential pair list class.
023 * @param <C> coefficient type
024 * @author Heinz Kredel
025 */
026
027public class GroebnerBaseSeqPairSeq<C extends RingElem<C>> extends GroebnerBaseAbstract<C> {
028
029
030    private static final Logger logger = LogManager.getLogger(GroebnerBaseSeqPairSeq.class);
031
032
033    private static final boolean debug = logger.isDebugEnabled();
034
035
036    /**
037     * Constructor.
038     */
039    public GroebnerBaseSeqPairSeq() {
040        super();
041    }
042
043
044    /**
045     * Constructor.
046     * @param red Reduction engine
047     */
048    public GroebnerBaseSeqPairSeq(Reduction<C> red) {
049        super(red);
050    }
051
052
053    /**
054     * Groebner base using pairlist class.
055     * @param modv module variable number.
056     * @param F polynomial list.
057     * @return GB(F) a Groebner base of F.
058     */
059    public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) {
060        List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>();
061        if (F == null) {
062            return G;
063        }
064        GenPolynomial<C> p;
065        CriticalPairList<C> pairlist = null;
066        int len = F.size();
067        ListIterator<GenPolynomial<C>> it = F.listIterator();
068        while (it.hasNext()) {
069            p = it.next();
070            if (p.length() > 0) {
071                p = p.monic();
072                if (p.isONE()) {
073                    G.clear();
074                    G.add(p);
075                    return G; // since no threads are activated
076                }
077                G.add(p);
078                if (pairlist == null) {
079                    pairlist = new CriticalPairList<C>(modv, p.ring);
080                }
081                // putOne not required
082                pairlist.put(p);
083            } else {
084                len--;
085            }
086        }
087        if (len <= 1) {
088            return G; // since no threads are activated
089        }
090
091        CriticalPair<C> pair;
092        GenPolynomial<C> pi;
093        GenPolynomial<C> pj;
094        GenPolynomial<C> S;
095        GenPolynomial<C> H;
096        while (pairlist.hasNext()) {
097            pair = pairlist.getNext();
098            if (pair == null) {
099                pairlist.update(); // ?
100                continue;
101            }
102            pi = pair.pi;
103            pj = pair.pj;
104            if (debug) {
105                logger.debug("pi    = {}", pi);
106                logger.debug("pj    = {}", pj);
107            }
108
109            S = red.SPolynomial(pi, pj);
110            if (S.isZERO()) {
111                pairlist.update(pair, S);
112                continue;
113            }
114            if (debug) {
115                logger.debug("ht(S) = {}", S.leadingExpVector());
116            }
117
118            H = red.normalform(G, S);
119            if (H.isZERO()) {
120                pairlist.update(pair, H);
121                continue;
122            }
123            if (debug) {
124                logger.debug("ht(H) = {}", H.leadingExpVector());
125            }
126
127            H = H.monic();
128            if (H.isONE()) {
129                // pairlist.record( pair, H );
130                G.clear();
131                G.add(H);
132                return G; // since no threads are activated
133            }
134            if (debug) {
135                logger.debug("H = {}", H);
136            }
137            G.add(H);
138            pairlist.update(pair, H);
139            //pairlist.update();
140        }
141        logger.debug("#sequential list = {}", G.size());
142        G = minimalGB(G);
143        logger.info("{}", pairlist);
144        return G;
145    }
146
147
148    /**
149     * Extended Groebner base using critical pair class.
150     * @param modv module variable number.
151     * @param F polynomial list.
152     * @return a container for an extended Groebner base of F.
153     */
154    @Override
155    public ExtendedGB<C> extGB(int modv, List<GenPolynomial<C>> F) {
156        if ( F == null || F.isEmpty() ) {
157            throw new IllegalArgumentException("null or empty F not allowed");
158        }
159        List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>();
160        List<List<GenPolynomial<C>>> F2G = new ArrayList<List<GenPolynomial<C>>>();
161        List<List<GenPolynomial<C>>> G2F = new ArrayList<List<GenPolynomial<C>>>();
162        CriticalPairList<C> pairlist = null;
163        boolean oneInGB = false;
164        int len = F.size();
165
166        List<GenPolynomial<C>> row = null;
167        List<GenPolynomial<C>> rows = null;
168        List<GenPolynomial<C>> rowh = null;
169        GenPolynomialRing<C> ring = null;
170        GenPolynomial<C> H;
171        GenPolynomial<C> p;
172
173        int nzlen = 0;
174        for (GenPolynomial<C> f : F) {
175            if (f.length() > 0) {
176                nzlen++;
177            }
178            if (ring == null) {
179                ring = f.ring;
180            }
181        }
182        GenPolynomial<C> mone = ring.getONE(); //.negate();
183        int k = 0;
184        ListIterator<GenPolynomial<C>> it = F.listIterator();
185        while (it.hasNext()) {
186            p = it.next();
187            if (p.length() > 0) {
188                row = blas.genVector(nzlen, null);
189                //C c = p.leadingBaseCoefficient();
190                //c = c.inverse();
191                //p = p.multiply( c );
192                row.set(k, mone); //.multiply(c) );
193                k++;
194                if (p.isUnit()) {
195                    G.clear();
196                    G.add(p);
197                    G2F.clear();
198                    G2F.add(row);
199                    oneInGB = true;
200                    break;
201                }
202                G.add(p);
203                G2F.add(row);
204                if (pairlist == null) {
205                    pairlist = new CriticalPairList<C>(modv, p.ring);
206                }
207                // putOne not required
208                pairlist.put(p);
209            } else {
210                len--;
211            }
212        }
213        ExtendedGB<C> exgb;
214        if (len <= 1 || oneInGB) {
215            // adjust F2G
216            for (GenPolynomial<C> f : F) {
217                row = blas.genVector(G.size(), null);
218                H = red.normalform(row, G, f);
219                if (!H.isZERO()) {
220                    logger.error("nonzero H = {}", H);
221                }
222                F2G.add(row);
223            }
224            exgb = new ExtendedGB<C>(F, G, F2G, G2F);
225            //System.out.println("exgb 1 = " + exgb);
226            return exgb;
227        }
228
229        CriticalPair<C> pair;
230        int i, j;
231        GenPolynomial<C> pi;
232        GenPolynomial<C> pj;
233        GenPolynomial<C> S;
234        GenPolynomial<C> x;
235        GenPolynomial<C> y;
236        //GenPolynomial<C> z;
237        while (pairlist.hasNext() && !oneInGB) {
238            pair = pairlist.getNext();
239            if (pair == null) {
240                pairlist.update(); // ?
241                continue;
242            }
243            i = pair.i;
244            j = pair.j;
245            pi = pair.pi;
246            pj = pair.pj;
247            if (debug) {
248                logger.info("i, pi    = {}, {}", i, pi);
249                logger.info("j, pj    = {}, {}", j, pj);
250            }
251
252            rows = new ArrayList<GenPolynomial<C>>(G.size());
253            for (int m = 0; m < G.size(); m++) {
254                rows.add(null);
255            }
256            S = red.SPolynomial(rows, i, pi, j, pj);
257            if (debug) {
258                logger.debug("is reduction S = {}", red.isReductionNF(rows, G, ring.getZERO(), S));
259            }
260            if (S.isZERO()) {
261                pairlist.update(pair, S);
262                // do not add to G2F
263                continue;
264            }
265            if (debug) {
266                logger.debug("ht(S) = {}", S.leadingExpVector());
267            }
268
269            rowh = new ArrayList<GenPolynomial<C>>(G.size());
270            for (int m = 0; m < G.size(); m++) {
271                rowh.add(null);
272            }
273            H = red.normalform(rowh, G, S);
274            if (debug) {
275                logger.debug("is reduction H = {}", red.isReductionNF(rowh, G, S, H));
276            }
277            if (H.isZERO()) {
278                pairlist.update(pair, H);
279                // do not add to G2F
280                continue;
281            }
282            if (debug) {
283                logger.debug("ht(H) = {}", H.leadingExpVector());
284            }
285
286            row = blas.vectorCombineOld(rows,rowh);
287            // if (debug) {
288            //     logger.debug("is reduction 0+sum(row,G) == H : "
289            //             + red.isReductionNF(row, G, H, ring.getZERO()));
290            // }
291
292            //  H = H.monic();
293            C c = H.leadingBaseCoefficient();
294            c = c.inverse();
295            H = H.multiply(c);
296            row = blas.scalarProduct(mone.multiply(c), row);
297            row.set(G.size(), mone);
298            if (H.isONE()) {
299                // pairlist.record( pair, H );
300                // G.clear(); 
301                G.add(H);
302                G2F.add(row);
303                oneInGB = true;
304                break;
305            }
306            if (debug) {
307                logger.debug("H = {}", H);
308            }
309            G.add(H);
310            pairlist.update(pair, H);
311            G2F.add(row);
312        }
313        if (debug) {
314            exgb = new ExtendedGB<C>(F, G, F2G, G2F);
315            logger.info("exgb unnorm = {}", exgb);
316        }
317        G2F = normalizeMatrix(F.size(), G2F);
318        if (debug) {
319            exgb = new ExtendedGB<C>(F, G, F2G, G2F);
320            logger.info("exgb nonmin = {}", exgb);
321            boolean t2 = isReductionMatrix(exgb);
322            logger.info("exgb t2 = {}", t2);
323        }
324        exgb = minimalExtendedGB(F.size(), G, G2F);
325        G = exgb.G;
326        G2F = exgb.G2F;
327        logger.debug("#sequential list = {}", G.size());
328        logger.info("{}", pairlist);
329        // setup matrices F and F2G
330        for (GenPolynomial<C> f : F) {
331            row = blas.genVector(G.size(), null);
332            H = red.normalform(row, G, f);
333            if (!H.isZERO()) {
334                logger.error("nonzero H = {}", H);
335            }
336            F2G.add(row);
337        }
338        exgb = new ExtendedGB<C>(F, G, F2G, G2F);
339        if (debug) {
340            logger.info("exgb nonmin = {}", exgb);
341            boolean t2 = isReductionMatrix(exgb);
342            logger.info("exgb t2 = {}", t2);
343        }
344        return exgb;
345    }
346
347}