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