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