001/*
002 * $Id: GroebnerBaseSigSeqIter.java 5869 2018-07-20 15:53:10Z kredel $
003 */
004
005package edu.jas.gb;
006
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.Collections;
011
012import org.apache.logging.log4j.Logger;
013import org.apache.logging.log4j.LogManager; 
014
015import edu.jas.poly.ExpVector;
016import edu.jas.poly.GenPolynomial;
017import edu.jas.poly.GenPolynomialRing;
018import edu.jas.poly.OrderedPolynomialList;
019import edu.jas.poly.PolyUtil;
020import edu.jas.structure.RingElem;
021
022
023/**
024 * Groebner Base signature based sequential iterative algorithm. Implements
025 * Groebner bases after the paper
026 * "Signature-based Algorithms to Compute Gröbner Bases" by Christian Eder and
027 * John Perry, ISSAC 2011. Compare the jython+JAS code in
028 * examples/basic_sigbased_gb.py. Originally the Python+Sage code is from
029 * http://www.math.usm.edu/perry/Research/basic_sigbased_gb.py
030 * 
031 * @param <C> coefficient type
032 * @author Heinz Kredel
033 * 
034 * @see edu.jas.application.GBAlgorithmBuilder
035 * @see edu.jas.gbufd.GBFactory
036 * @see edu.jas.gb.GroebnerBaseGGVSigSeqIter
037 * @see edu.jas.gb.GroebnerBaseArriSigSeqIter
038 * @see edu.jas.gb.GroebnerBaseF5zSigSeqIter
039 */
040
041public class GroebnerBaseSigSeqIter<C extends RingElem<C>> extends GroebnerBaseAbstract<C> {
042
043
044    private static final Logger logger = LogManager.getLogger(GroebnerBaseSigSeqIter.class);
045
046
047    private static final boolean debug = logger.isDebugEnabled();
048
049
050    final SigReductionSeq<C> sred;
051
052
053    /**
054     * Constructor.
055     */
056    public GroebnerBaseSigSeqIter() {
057        this(new SigReductionSeq<C>());
058    }
059
060
061    /**
062     * Constructor.
063     * @param red Reduction engine
064     */
065    public GroebnerBaseSigSeqIter(SigReductionSeq<C> red) {
066        super();
067        sred = red;
068    }
069
070
071    /**
072     * Groebner base signature iterative algorithm.
073     * @param modv module variable number.
074     * @param F polynomial list.
075     * @return GB(F) a Groebner base of F.
076     */
077    public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) {
078        List<GenPolynomial<C>> G = normalizeZerosOnes(F);
079        G = PolyUtil.<C> monic(G);
080        if (G.size() <= 1) {
081            return G;
082        }
083        // sort, no reverse
084        //  G = OrderedPolynomialList.<C> sort(G);
085        G = OrderedPolynomialList.<C> sortDegree(G);
086        //no: Collections.reverse(G);
087        logger.info("G-sort = " + G);
088        List<GenPolynomial<C>> Gp = new ArrayList<GenPolynomial<C>>();
089        for (GenPolynomial<C> p : G) {
090            if (logger.isInfoEnabled()) {
091                logger.info("p = " + p);
092            }
093            GenPolynomial<C> pp = red.normalform(Gp, p);
094            if (pp.isZERO()) {
095                continue;
096            }
097            Gp = GB(modv, Gp, p);
098            if (Gp.size() > 0) {
099                if (Gp.get(0).isONE()) {
100                    return Gp;
101                }
102            }
103        }
104        return Gp;
105    }
106
107
108    /**
109     * Groebner base iterated.
110     * @param modv module variable number.
111     * @param G polynomial list of a Groebner base.
112     * @param f polynomial.
113     * @return GB(G,f) a Groebner base of G+(f).
114     */
115    public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> G, GenPolynomial<C> f) {
116        List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(G);
117        GenPolynomial<C> g = f.monic();
118        if (F.isEmpty()) {
119            F.add(g);
120            return F; // commutative
121        }
122        if (g.isZERO()) {
123            return F;
124        }
125        if (g.isONE()) {
126            F.clear();
127            F.add(g);
128            return F;
129        }
130        GenPolynomialRing<C> ring = F.get(0).ring;
131        if (!ring.coFac.isField()) {
132            throw new IllegalArgumentException("coefficients not from a field");
133        }
134        if (modv != 0) {
135            throw new UnsupportedOperationException("motv != 0 not implemented");
136        }
137        // add signatures
138        List<SigPoly<C>> Gs = new ArrayList<SigPoly<C>>();
139        for (GenPolynomial<C> p : F) {
140            Gs.add(new SigPoly<C>(ring.getZERO(), p));
141        }
142        SigPoly<C> gs = new SigPoly<C>(ring.getONE(), g);
143        Gs.add(gs);
144        //logger.info("Gs = " + Gs);
145        // construct critical pair list
146        List<SigPair<C>> pairlist = new ArrayList<SigPair<C>>();
147        for (SigPoly<C> p : Gs) { // F via continue
148            if (p.poly.equals(g)) {
149                continue;
150            }
151            pairlist.add(newPair(gs, p, Gs));
152        }
153        //logger.info("start " + pairlist.size());
154        logger.info("start " + Gs);
155
156        List<ExpVector> syz = initializeSyz(F, Gs);
157        List<SigPoly<C>> done = new ArrayList<SigPoly<C>>();
158
159        SigPair<C> pair;
160        //SigPoly<C> pi, pj;
161        GenPolynomial<C> S, H, sigma;
162        while (!pairlist.isEmpty()) {
163            pairlist = pruneP(pairlist, syz);
164            if (pairlist.isEmpty()) {
165                continue;
166            }
167            List<SigPair<C>>[] spl = sred.minDegSubset(pairlist);
168            List<SigPair<C>> Sl = spl[0];
169            long mdeg = sred.minimalSigDegree(Sl);
170            pairlist = spl[1];
171            logger.info("treating " + Sl.size() + " signatures of degree " + mdeg);
172            //logger.info("Sl(" + mdeg + ") = " + Sl);
173            while (!Sl.isEmpty()) {
174                //logger.info("Sl_full = " + sred.sigmas(Sl));
175                Sl = pruneS(Sl, syz, done, Gs);
176                if (Sl.isEmpty()) {
177                    continue;
178                }
179                Sl = sred.sortSigma(Sl);
180                //logger.info("Sl_sort = " + Sl);
181                pair = Sl.remove(0);
182                if (pair == null) {
183                    continue;
184                }
185                //logger.info("sigma = " + pair.sigma);
186                S = SPolynomial(pair);
187                SigPoly<C> Ss = new SigPoly<C>(pair.sigma, S);
188                if (S.isZERO()) {
189                    updateSyz(syz, Ss);
190                    done.add(Ss);
191                    continue;
192                }
193                if (debug) {
194                    logger.debug("ht(S) = " + S.leadingExpVector());
195                }
196
197                SigPoly<C> Hs = sigNormalform(F, Gs, Ss);
198                H = Hs.poly;
199                sigma = Hs.sigma;
200                if (debug) {
201                    logger.info("new polynomial = " + Hs); //.leadingExpVector() );
202                }
203                if (H.isZERO()) {
204                    updateSyz(syz, Hs);
205                    done.add(Hs);
206                    continue;
207                }
208                H = H.monic();
209                if (debug) {
210                    logger.info("ht(H) = " + H.leadingExpVector());
211                }
212
213                if (H.isONE()) {
214                    G.clear();
215                    G.add(H);
216                    logger.info("end " + pairlist);
217                    return G; // since no threads are activated
218                }
219                if (sred.isSigRedundant(Gs, Hs)) {
220                    continue;
221                }
222                if (logger.isInfoEnabled()) {
223                    //logger.info("sigma::h = " + sigma + " :: " + ring.toScript(H.leadingExpVector()));
224                    logger.info("sigma::h = " + sigma + " :: " + H.leadingExpVector());
225                }
226                if (H.length() > 0) {
227                    for (SigPoly<C> p : Gs) {
228                        if (p.poly.isZERO()) {
229                            continue;
230                        }
231                        GenPolynomial<C> tau = p.sigma;
232                        GenPolynomial<C>[] mult = SPolynomialFactors(Hs, p);
233                        //System.out.print("sigma = " + sigma + ", tau = " + tau);
234                        //System.out.println(", mult  = " + Arrays.toString(mult));
235                        ExpVector se = sigma.leadingExpVector();
236                        ExpVector te = tau.leadingExpVector();
237                        if (mult[0].multiply(se).equals(mult[1].multiply(te))) {
238                            //logger.info("skip by sigma");
239                            continue;
240                        }
241                        SigPair<C> pp;
242                        //boolean xy = mult[0].multiply(se).compareTo(mult[1].multiply(te)) > 0;
243                        if (mult[0].multiply(se).compareTo(mult[1].multiply(te)) > 0) {
244                            pp = newPair(sigma.multiply(mult[0]), Hs, p, Gs);
245                        } else {
246                            pp = newPair(tau.multiply(mult[1]), p, Hs, Gs);
247                        }
248                        //System.out.println("new_pair " + pp.sigma + ", xy = " + xy + ", sigma = " + sigma + ", tau = " + tau + ", mult  = " + Arrays.toString(mult) + ", m0*se = " + mult[0].multiply(se) + ", m1*te = " + mult[1].multiply(te) );
249                        if (pp.sigma.degree() == mdeg) { // mdeg is sigma.degree()
250                            Sl.add(pp); // do not check contains
251                        } else {
252                            pairlist.add(pp); // do not check contains
253                        }
254                    }
255                    Gs.add(Hs);
256                    done.add(Hs);
257                }
258            }
259        }
260        logger.info("#sequential list before reduction = " + Gs.size());
261        List<GenPolynomial<C>> Gp = sred.polys(Gs);
262        //logger.info("G_full = " + Gp);
263        G = minimalGB(Gp);
264        //G = red.irreducibleSet(Gp);
265        //G = OrderedPolynomialList.<C> sortDegree(G);
266        //logger.info("G_reduced = " + G);
267        logger.info("end " + pairlist);
268        return G;
269    }
270
271
272    /**
273     * S-Polynomial.
274     * @param A monic polynomial.
275     * @param B monic polynomial.
276     * @return spol(A,B) the S-polynomial of the A and B.
277     */
278    GenPolynomial<C> SPolynomial(SigPoly<C> A, SigPoly<C> B) {
279        return sred.SPolynomial(A, B);
280    }
281
282
283    /**
284     * S-Polynomial.
285     * @param P pair.
286     * @return spol(A,B) the S-polynomial of the pair (A,B).
287     */
288    GenPolynomial<C> SPolynomial(SigPair<C> P) {
289        return sred.SPolynomial(P.pi, P.pj);
290    }
291
292
293    /**
294     * S-Polynomial polynomial factors.
295     * @param A monic polynomial.
296     * @param B monic polynomial.
297     * @return polynomials [e,f] such that spol(A,B) = e*a - f*B.
298     */
299    GenPolynomial<C>[] SPolynomialFactors(SigPoly<C> A, SigPoly<C> B) {
300        return sred.SPolynomialFactors(A, B);
301    }
302
303
304    /**
305     * Pair with signature.
306     * @param A polynomial with signature.
307     * @param B polynomial with signature.
308     * @param G polynomial ith signature list.
309     * @return signature pair according to algorithm.
310     */
311    SigPair<C> newPair(SigPoly<C> A, SigPoly<C> B, List<SigPoly<C>> G) {
312        ExpVector e = A.poly.leadingExpVector().lcm(B.poly.leadingExpVector())
313                        .subtract(A.poly.leadingExpVector());
314        return new SigPair<C>(e, A, B, G);
315    }
316
317
318    /**
319     * Pair with signature.
320     * @param s signature for pair.
321     * @param A polynomial with signature.
322     * @param B polynomial with signature.
323     * @param G polynomial ith signature list.
324     * @return signature pair according to algorithm.
325     */
326    SigPair<C> newPair(GenPolynomial<C> s, SigPoly<C> A, SigPoly<C> B, List<SigPoly<C>> G) {
327        return new SigPair<C>(s, A, B, G);
328    }
329
330
331    /**
332     * Top normalform.
333     * @param A polynomial.
334     * @param F polynomial list.
335     * @param G polynomial list.
336     * @return nf(A) with respect to F and G.
337     */
338    SigPoly<C> sigNormalform(List<GenPolynomial<C>> F, List<SigPoly<C>> G, SigPoly<C> A) {
339        return sred.sigNormalform(F, G, A);
340    }
341
342
343    /**
344     * Prune total pair list P.
345     * @param P pair list.
346     * @param syz list of exponent vectors representing syzygies.
347     * @return updated pair list.
348     */
349    List<SigPair<C>> pruneP(List<SigPair<C>> P, List<ExpVector> syz) {
350        if (debug) {
351            logger.debug("unused " + syz);
352        }
353        return P;
354    }
355
356
357    /**
358     * Prune pair list of degree d.
359     * @param S pair list.
360     * @param syz list of exponent vectors representing syzygies.
361     * @param done list of treated polynomials.
362     * @param G polynomial with signature list.
363     * @return updated pair list.
364     */
365    List<SigPair<C>> pruneS(List<SigPair<C>> S, List<ExpVector> syz, List<SigPoly<C>> done,
366                    List<SigPoly<C>> G) {
367        if (debug) {
368            logger.debug("unused " + syz + " " + done + " " + G);
369        }
370        return S;
371    }
372
373
374    /**
375     * Initializes syzygy list.
376     * @param F polynomial list.
377     * @param G polynomial with signature list.
378     * @return list of exponent vectors representing syzygies.
379     */
380    List<ExpVector> initializeSyz(List<GenPolynomial<C>> F, List<SigPoly<C>> G) {
381        if (debug) {
382            logger.debug("unused " + G + " " + F);
383        }
384        List<ExpVector> P = new ArrayList<ExpVector>();
385        return P;
386    }
387
388
389    /**
390     * Update syzygy list.
391     * @param syz list of exponent vectors representing syzygies.
392     * @param r polynomial. <b>Note:</b> szy is modified to represent updated
393     *            list of exponent vectors.
394     */
395    void updateSyz(List<ExpVector> syz, SigPoly<C> r) {
396        if (debug) {
397            logger.debug("unused " + syz + " " + r);
398        }
399        return;
400    }
401
402}