001/*
002 * $Id: GroebnerBaseFGLM.java 5687 2017-01-03 08:44:03Z kredel $
003 */
004
005package edu.jas.gbufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import org.apache.log4j.Logger;
012
013import edu.jas.gb.GroebnerBaseAbstract;
014import edu.jas.gb.PairList;
015import edu.jas.gb.Reduction;
016import edu.jas.gb.ReductionSeq;
017import edu.jas.poly.ExpVector;
018import edu.jas.poly.GenPolynomial;
019import edu.jas.poly.GenPolynomialRing;
020import edu.jas.poly.PolyUtil;
021import edu.jas.poly.TermOrder;
022import edu.jas.structure.GcdRingElem;
023import edu.jas.structure.RingFactory;
024
025
026/**
027 * Groebner Base sequential FGLM algorithm. Implements Groebner base computation
028 * via FGLM algorithm.
029 * @param <C> coefficient type
030 * @author Jan Suess
031 *
032 * @see edu.jas.application.GBAlgorithmBuilder
033 * @see edu.jas.gbufd.GBFactory
034 */
035public class GroebnerBaseFGLM<C extends GcdRingElem<C>> extends GroebnerBaseAbstract<C> {
036
037
038    private static final Logger logger = Logger.getLogger(GroebnerBaseFGLM.class);
039
040
041    //private static final boolean debug = logger.isDebugEnabled();
042
043
044    /**
045     * The backing GB algorithm implementation.
046     */
047    private GroebnerBaseAbstract<C> sgb;
048
049
050    /**
051     * Constructor.
052     */
053    public GroebnerBaseFGLM() {
054        super();
055        sgb = null;
056    }
057
058
059    /**
060     * Constructor.
061     * @param red Reduction engine
062     */
063    public GroebnerBaseFGLM(Reduction<C> red) {
064        super(red);
065        sgb = null;
066    }
067
068
069    /**
070     * Constructor.
071     * @param red Reduction engine
072     * @param pl pair selection strategy
073     */
074    public GroebnerBaseFGLM(Reduction<C> red, PairList<C> pl) {
075        super(red, pl);
076        sgb = null;
077    }
078
079
080    /**
081     * Constructor.
082     * @param red Reduction engine
083     * @param pl pair selection strategy
084     * @param gb backing GB algorithm.
085     */
086    public GroebnerBaseFGLM(Reduction<C> red, PairList<C> pl, GroebnerBaseAbstract<C> gb) {
087        super(red, pl);
088        sgb = gb;
089    }
090
091
092    /**
093     * Constructor.
094     * @param gb backing GB algorithm.
095     */
096    public GroebnerBaseFGLM(GroebnerBaseAbstract<C> gb) {
097        super();
098        sgb = gb;
099    }
100
101
102    /**
103     * Get the String representation with GB engine.
104     * @see java.lang.Object#toString()
105     */
106    @Override
107    public String toString() {
108        if (sgb == null) {
109            return "GroebnerBaseFGLM()";
110        }
111        return "GroebnerBaseFGLM( " + sgb.toString() + " )";
112    }
113
114
115    /**
116     * Groebner base using FGLM algorithm.
117     * @param modv module variable number.
118     * @param F polynomial list.
119     * @return GB(F) a inv lex term order Groebner base of F.
120     */
121    public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) {
122        if (modv != 0) {
123            throw new UnsupportedOperationException("case modv != 0 not yet implemented");
124        }
125        if (F == null || F.size() == 0) {
126            return F;
127        }
128        List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>();
129        if (F.size() <= 1) {
130            GenPolynomial<C> p = F.get(0).monic();
131            G.add(p);
132            return G;
133        }
134        // convert to graded term order
135        List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F.size());
136        GenPolynomialRing<C> pfac = F.get(0).ring;
137        if (!pfac.coFac.isField()) {
138            throw new IllegalArgumentException("coefficients not from a field: " + pfac.coFac);
139        }
140        TermOrder tord = new TermOrder(TermOrder.IGRLEX);
141        GenPolynomialRing<C> gfac = new GenPolynomialRing<C>(pfac.coFac, pfac.nvar, tord, pfac.getVars());
142        for (GenPolynomial<C> p : F) {
143            GenPolynomial<C> g = gfac.copy(p); // change term order
144            Fp.add(g);
145        }
146        // compute graded term order Groebner base
147        if (sgb == null) {
148            sgb = GBFactory.<C> getImplementation(pfac.coFac, strategy);
149        }
150        List<GenPolynomial<C>> Gp = sgb.GB(modv, Fp);
151        logger.info("graded GB = " + Gp);
152        if (tord.equals(pfac.tord)) {
153            return Gp;
154        }
155        if (Gp.size() == 0) {
156            return Gp;
157        }
158        if (Gp.size() == 1) { // also dimension -1
159            GenPolynomial<C> p = pfac.copy(Gp.get(0)); // change term order
160            G.add(p);
161            return G;
162        }
163        // check dimension zero
164        int z = commonZeroTest(Gp);
165        if (z > 0) {
166            logger.error("use Groebner Walk algorithm");
167            throw new IllegalArgumentException("ideal(G) not zero dimensional, dim =  " + z);
168        }
169        // compute invlex Groebner base via FGLM
170        G = convGroebnerToLex(Gp);
171        return G;
172    }
173
174
175    /**
176     * Algorithm CONVGROEBNER: Converts Groebner bases w.r.t. total degree
177     * termorder into Groebner base w.r.t to inverse lexicographical term order
178     * @return Groebner base w.r.t to inverse lexicographical term order
179     */
180    public List<GenPolynomial<C>> convGroebnerToLex(List<GenPolynomial<C>> groebnerBasis) {
181        if (groebnerBasis == null || groebnerBasis.size() == 0) {
182            throw new IllegalArgumentException("G may not be null or empty");
183        }
184        //Polynomial ring of input Groebnerbasis G
185        GenPolynomialRing<C> ring = groebnerBasis.get(0).ring;
186        int numberOfVariables = ring.nvar; //Number of Variables of the given Polynomial Ring
187        String[] ArrayOfVariables = ring.getVars(); //Variables of given polynomial ring w.r.t. to input G
188        RingFactory<C> cfac = ring.coFac;
189
190        //Main Algorithm
191        //Initialization
192
193        TermOrder invlex = new TermOrder(TermOrder.INVLEX);
194        //Polynomial ring of newGB with invlex order
195        GenPolynomialRing<C> ufac = new GenPolynomialRing<C>(cfac, numberOfVariables, invlex,
196                        ArrayOfVariables);
197
198        //Local Lists
199        List<GenPolynomial<C>> newGB = new ArrayList<GenPolynomial<C>>(); //Instantiate the return list of polynomials
200        List<GenPolynomial<C>> H = new ArrayList<GenPolynomial<C>>(); //Instantiate a help list of polynomials
201        List<GenPolynomial<C>> redTerms = new ArrayList<GenPolynomial<C>>();//Instantiate the return list of reduced terms
202
203        //Local Polynomials
204        GenPolynomial<C> t = ring.ONE; //Create ONE polynom of original polynomial ring
205        GenPolynomial<C> h; //Create help polynomial
206        GenPolynomial<GenPolynomial<C>> hh; //h as polynomial in rfac
207        GenPolynomial<GenPolynomial<C>> p; //Create another help polynomial
208        redTerms.add(t); //Add ONE to list of reduced terms
209
210        //create new indeterminate Y1
211        int indeterminates = 1; //Number of indeterminates, starting with Y1
212        GenPolynomialRing<C> cpfac = createRingOfIndeterminates(ring, indeterminates);
213        GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cpfac, ring);
214        GenPolynomial<GenPolynomial<C>> q = rfac.getZERO().sum(cpfac.univariate(0));
215
216        //Main while loop
217        int z = -1;
218        t = lMinterm(H, t);
219        while (t != null) {
220            //System.out.println("t = " + t);
221            h = red.normalform(groebnerBasis, t);
222            //System.out.println("Zwischennormalform h = " + h.toString());
223            hh = PolyUtil.<C> toRecursive(rfac, h);
224            p = hh.sum(q);
225            List<GenPolynomial<C>> Cf = new ArrayList<GenPolynomial<C>>(p.getMap().values());
226            Cf = red.irreducibleSet(Cf);
227            //System.out.println("Cf = " + Cf);
228            //System.out.println("Current Polynomial ring in Y_n: " + rfac.toString());
229
230            z = commonZeroTest(Cf);
231            //System.out.println("z = " + z);
232            if (z != 0) { //z=1 OR z=-1 --> Infinite number of solutions OR No solution
233                indeterminates++; //then, increase number of indeterminates by one
234                redTerms.add(t); //add current t to list of reduced terms
235                cpfac = addIndeterminate(cpfac);
236                rfac = new GenPolynomialRing<GenPolynomial<C>>(cpfac, ring);
237                hh = PolyUtil.<C> toRecursive(rfac, h);
238                GenPolynomial<GenPolynomial<C>> Yt = rfac.getZERO().sum(cpfac.univariate(0));
239                GenPolynomial<GenPolynomial<C>> Yth = hh.multiply(Yt);
240                q = PolyUtil.<C> extendCoefficients(rfac, q, 0, 0L);
241                q = Yth.sum(q);
242            } else { // z=0 --> one solution
243                GenPolynomial<C> g = ufac.getZERO();
244                for (GenPolynomial<C> pc : Cf) {
245                    ExpVector e = pc.leadingExpVector();
246                    //System.out.println("e = " + e);
247                    if (e == null) {
248                        continue;
249                    }
250                    int[] v = e.dependencyOnVariables();
251                    if (v == null || v.length == 0) {
252                        continue;
253                    }
254                    int vi = v[0];
255                    vi = indeterminates - vi;
256                    C tc = pc.trailingBaseCoefficient();
257                    if (!tc.isZERO()) {
258                        tc = tc.negate();
259                        GenPolynomial<C> csRedterm = redTerms.get(vi - 1).multiply(tc);
260                        //System.out.println("csRedterm = " + csRedterm);
261                        g = g.sum(csRedterm);
262                    }
263                }
264                g = g.sum(t);
265                g = ufac.copy(g);
266                H.add(t);
267                if (!g.isZERO()) {
268                    newGB.add(g);
269                    logger.info("new element for GB = " + g.leadingExpVector());
270                }
271            }
272            t = lMinterm(H, t); // compute lMINTERM of current t (lexMinterm)
273        }
274        //logger.info("GB = " + newGB);
275        return newGB;
276    }
277
278
279    /**
280     * Algorithm lMinterm: MINTERM algorithm for inverse lexicographical term
281     * order.
282     * @param t Term
283     * @param G Groebner basis
284     * @return Term that specifies condition (D) or null (Condition (D) in
285     *         "A computational approach to commutative algebra", Becker,
286     *         Weispfenning, Kredel 1993, p. 427)
287     */
288    public GenPolynomial<C> lMinterm(List<GenPolynomial<C>> G, GenPolynomial<C> t) {
289        //not ok: if ( G == null || G.size() == 0 ) ...
290        GenPolynomialRing<C> ring = t.ring;
291        int numberOfVariables = ring.nvar;
292        GenPolynomial<C> u = new GenPolynomial<C>(ring, t.leadingBaseCoefficient(), t.leadingExpVector()); //HeadTerm of of input polynomial
293        ReductionSeq<C> redHelp = new ReductionSeq<C>(); // Create instance of ReductionSeq to use method isReducible
294        //not ok: if ( redHelp.isTopReducible(G,u) ) ...
295        for (int i = numberOfVariables - 1; i >= 0; i--) { // Walk through all variables, starting with least w.r.t to lex-order
296            GenPolynomial<C> x = ring.univariate(i); // Create Linear Polynomial X_i
297            u = u.multiply(x); // Multiply current u with x
298            if (!redHelp.isTopReducible(G, u)) { // Check if any term in HT(G) divides current u
299                return u;
300            }
301            GenPolynomial<C> s = ring.univariate(i, u.degree(numberOfVariables - (i + 1))); //if not, eliminate variable x_i
302            u = u.divide(s);
303        }
304        return null;
305    }
306
307
308    /**
309     * Compute the residues to given polynomial list.
310     * @return List of reduced terms
311     */
312    public List<GenPolynomial<C>> redTerms(List<GenPolynomial<C>> groebnerBasis) {
313        if (groebnerBasis == null || groebnerBasis.size() == 0) {
314            throw new IllegalArgumentException("groebnerBasis may not be null or empty");
315        }
316        GenPolynomialRing<C> ring = groebnerBasis.get(0).ring;
317        int numberOfVariables = ring.nvar; //Number of Variables of the given Polynomial Ring
318        long[] degrees = new long[numberOfVariables]; //Array for the degree-limits for the reduced terms
319
320        List<GenPolynomial<C>> terms = new ArrayList<GenPolynomial<C>>(); //Instantiate the return object
321        for (GenPolynomial<C> g : groebnerBasis) { //For each polynomial of G
322            if (g.isONE()) {
323                terms.clear();
324                return terms; //If 1 e G, return empty list terms
325            }
326            ExpVector e = g.leadingExpVector(); //Take the exponent of the leading monomial             
327            if (e.totalDeg() == e.maxDeg()) { //and check, whether a variable x_i is isolated
328                for (int i = 0; i < numberOfVariables; i++) {
329                    long exp = e.getVal(i);
330                    if (exp > 0) {
331                        degrees[i] = exp; //if true, add the degree of univariate x_i to array degrees
332                    }
333                }
334            }
335        }
336        long max = maxArray(degrees); //Find maximum in Array degrees
337        for (int i = 0; i < degrees.length; i++) { //Set all zero grades to maximum of array "degrees"
338            if (degrees[i] == 0) {
339                logger.info("dimension not zero, setting degree to " + max);
340                degrees[i] = max; //--> to "make" the ideal zero-dimensional
341            }
342        }
343        terms.add(ring.ONE); //Add the one-polynomial of the ring to the list of reduced terms
344        ReductionSeq<C> s = new ReductionSeq<C>(); //Create instance of ReductionSeq to use method isReducible
345
346        //Main Algorithm
347        for (int i = 0; i < numberOfVariables; i++) {
348            GenPolynomial<C> x = ring.univariate(i); //Create  Linear Polynomial X_i
349            List<GenPolynomial<C>> S = new ArrayList<GenPolynomial<C>>(terms); //Copy all entries of return list "terms" into list "S"
350            for (GenPolynomial<C> t : S) {
351                for (int l = 1; l <= degrees[i]; l++) {
352                    t = t.multiply(x); //Multiply current element t with Linear Polynomial X_i
353                    if (!s.isReducible(groebnerBasis, t)) { //Check, if t is irreducible mod groebnerbase
354                        terms.add(t); //Add t to return list terms
355                    }
356                }
357            }
358        }
359        return terms;
360    }
361
362
363    /**
364     * Internal method to create a polynomial ring in i indeterminates. Create
365     * new ring over coefficients of ring with i variables Y1,...,Yi
366     * (indeterminate)
367     * @return polynomial ring with variables Y1...Yi and coefficient of ring.
368     */
369    GenPolynomialRing<C> createRingOfIndeterminates(GenPolynomialRing<C> ring, int i) {
370        RingFactory<C> cfac = ring.coFac;
371        int indeterminates = i;
372        String[] stringIndeterminates = new String[indeterminates];
373        for (int j = 1; j <= indeterminates; j++) {
374            stringIndeterminates[j - 1] = ("Y" + j);
375        }
376        TermOrder invlex = new TermOrder(TermOrder.INVLEX);
377        GenPolynomialRing<C> cpfac = new GenPolynomialRing<C>(cfac, indeterminates, invlex,
378                        stringIndeterminates);
379        return cpfac;
380    }
381
382
383    /**
384     * Internal method to add new indeterminates. Add another variabe
385     * (indeterminate) Y_{i+1} to existing ring
386     * @return polynomial ring with variables Y1,..,Yi,Yi+1 and coefficients of
387     *         ring.
388     */
389    GenPolynomialRing<C> addIndeterminate(GenPolynomialRing<C> ring) {
390        String[] stringIndeterminates = new String[1];
391        int number = ring.nvar + 1;
392        stringIndeterminates[0] = ("Y" + number);
393        ring = ring.extend(stringIndeterminates);
394        return ring;
395    }
396
397
398    /**
399     * Maximum of an array.
400     * @return maximum of an array
401     */
402    long maxArray(long[] t) {
403        if (t.length == 0) {
404            return 0L;
405        }
406        long maximum = t[0];
407        for (int i = 1; i < t.length; i++) {
408            if (t[i] > maximum) {
409                maximum = t[i];
410            }
411        }
412        return maximum;
413    }
414
415
416    /**
417     * Cleanup and terminate ThreadPool.
418     */
419    @Override
420    public void terminate() {
421        if (sgb == null) {
422            return;
423        }
424        sgb.terminate();
425    }
426
427
428    /**
429     * Cancel ThreadPool.
430     */
431    @Override
432    public int cancel() {
433        if (sgb == null) {
434            return 0;
435        }
436        return sgb.cancel();
437    }
438
439}