001/*
002 * $Id: WordGroebnerBasePseudoRecSeq.java 5935 2018-09-30 11:47:20Z kredel $
003 */
004
005package edu.jas.gbufd;
006
007
008import java.util.ArrayList;
009import java.util.Collections;
010import java.util.List;
011
012import org.apache.logging.log4j.Logger;
013import org.apache.logging.log4j.LogManager; 
014
015import edu.jas.gb.OrderedWordPairlist;
016import edu.jas.gb.WordGroebnerBaseAbstract;
017import edu.jas.gb.WordPair;
018import edu.jas.gb.WordPairList;
019import edu.jas.poly.GenPolynomial;
020import edu.jas.poly.GenPolynomialRing;
021import edu.jas.poly.GenWordPolynomial;
022import edu.jas.poly.GenWordPolynomialRing;
023import edu.jas.poly.PolyUtil;
024import edu.jas.structure.GcdRingElem;
025import edu.jas.structure.RingFactory;
026import edu.jas.ufd.GCDFactory;
027import edu.jas.ufd.GreatestCommonDivisorAbstract;
028
029
030/**
031 * Non-commutative word Groebner Base sequential algorithm. Implements Groebner
032 * bases and GB test. Coefficients can for example be (commutative) multivariate
033 * polynomials.
034 * @param <C> coefficient type
035 * @author Heinz Kredel
036 */
037
038public class WordGroebnerBasePseudoRecSeq<C extends GcdRingElem<C>> extends
039                WordGroebnerBaseAbstract<GenPolynomial<C>> {
040
041
042    private static final Logger logger = LogManager.getLogger(WordGroebnerBasePseudoRecSeq.class);
043
044
045    private static final boolean debug = logger.isDebugEnabled();
046
047
048    /**
049     * Greatest common divisor engine for coefficient content and primitive
050     * parts.
051     */
052    protected final GreatestCommonDivisorAbstract<C> engine;
053
054
055    /**
056     * Reduction engine.
057     */
058    protected final WordPseudoReduction<C> redRec;
059
060
061    /**
062     * Reduction engine.
063     */
064    protected final WordPseudoReduction<GenPolynomial<C>> red;
065
066
067    /**
068     * Coefficient ring factory.
069     */
070    //protected final RingFactory<GenPolynomial<C>> cofac;
071    protected final GenPolynomialRing<C> cofac;
072
073
074    /**
075     * Constructor.
076     * @param rf coefficient ring factory.
077     */
078    public WordGroebnerBasePseudoRecSeq(RingFactory<GenPolynomial<C>> rf) {
079        this(rf, new WordPseudoReductionSeq<GenPolynomial<C>>());
080    }
081
082
083    /**
084     * Constructor.
085     * @param rf coefficient ring factory.
086     * @param red Reduction engine
087     */
088    public WordGroebnerBasePseudoRecSeq(RingFactory<GenPolynomial<C>> rf,
089                    WordPseudoReductionSeq<GenPolynomial<C>> red) {
090        this(rf, red, new OrderedWordPairlist<GenPolynomial<C>>());
091    }
092
093
094    /**
095     * Constructor.
096     * @param rf coefficient ring factory.
097     * @param red Reduction engine
098     * @param pl pair selection strategy
099     */
100    @SuppressWarnings("unchecked")
101    public WordGroebnerBasePseudoRecSeq(RingFactory<GenPolynomial<C>> rf,
102                    WordPseudoReductionSeq<GenPolynomial<C>> red, WordPairList<GenPolynomial<C>> pl) {
103        super(red, pl);
104        this.red = red;
105        redRec = (WordPseudoReduction<C>) (WordPseudoReduction) red;
106        cofac = (GenPolynomialRing<C>) rf;
107        if (!cofac.isCommutative()) {
108            logger.warn("reduction not correct for " + cofac.toScript());
109        }
110        engine = GCDFactory.<C> getImplementation(cofac.coFac);
111        //not used: engine = GCDFactory.<C>getProxy(cofac.coFac);
112    }
113
114
115    /**
116     * Word Groebner base using word pairlist class.
117     * @param F word polynomial list.
118     * @return GB(F) a finite non-commutative Groebner base of F, if it exists.
119     */
120    @Override
121    public List<GenWordPolynomial<GenPolynomial<C>>> GB(List<GenWordPolynomial<GenPolynomial<C>>> F) {
122        List<GenWordPolynomial<GenPolynomial<C>>> G = normalizeZerosOnes(F);
123        //G = PolyUtil.<C> wordMonic(G);
124        G = recursivePrimitivePart(G);
125        G = normalizeZerosOnes(G);
126        if (G.size() <= 1) {
127            return G;
128        }
129        GenWordPolynomialRing<GenPolynomial<C>> ring = G.get(0).ring;
130        if (!ring.coFac.isCommutative()) {
131            throw new IllegalArgumentException("coefficient ring not commutative");
132        }
133        //Collections.sort(G);
134        OrderedWordPairlist<GenPolynomial<C>> pairlist = (OrderedWordPairlist<GenPolynomial<C>>) strategy
135                        .create(ring);
136        pairlist.put(G);
137        logger.info("start " + pairlist);
138
139        WordPair<GenPolynomial<C>> pair;
140        GenWordPolynomial<GenPolynomial<C>> pi;
141        GenWordPolynomial<GenPolynomial<C>> pj;
142        List<GenWordPolynomial<GenPolynomial<C>>> S;
143        GenWordPolynomial<GenPolynomial<C>> H;
144        while (pairlist.hasNext()) {
145            pair = pairlist.removeNext();
146            //logger.debug("pair = " + pair);
147            if (pair == null) {
148                continue;
149            }
150            pi = pair.pi;
151            pj = pair.pj;
152            if (debug) {
153                logger.info("pi   = " + pi + ", pj = " + pj);
154                //logger.info("pj    = " + pj);
155            }
156
157            S = red.SPolynomials(pi, pj);
158            if (S.isEmpty()) {
159                continue;
160            }
161            for (GenWordPolynomial<GenPolynomial<C>> s : S) {
162                if (s.isZERO()) {
163                    //pair.setZero();
164                    continue;
165                }
166                if (debug) {
167                    logger.info("ht(S) = " + s.leadingWord());
168                }
169                boolean t = pairlist.criterion3(pair.i, pair.j, s.leadingWord());
170                //System.out.println("criterion3(" + pair.i + "," + pair.j + ") = " + t);
171                //if ( !t ) {
172                //    continue;  
173                //}
174
175                H = redRec.normalformRecursive(G, s);
176                if (debug) {
177                    //logger.info("pair = " + pair); 
178                    //logger.info("ht(S) = " + S.monic()); //.leadingWord() );
179                    logger.info("ht(H) = " + H.monic()); //.leadingWord() );
180                }
181                if (H.isZERO()) {
182                    //pair.setZero();
183                    continue;
184                }
185                if (!t) {
186                    logger.info("criterion3(" + pair.i + "," + pair.j + ") wrong: " + s.leadingWord()
187                                    + " --> '" + H.leadingWord() + "'");
188                }
189
190                //H = H.monic();
191                H = recursivePrimitivePart(H);
192                H = H.abs();
193                if (debug) {
194                    logger.info("ht(H) = " + H.leadingWord());
195                }
196                if (H.isONE()) {
197                    G.clear();
198                    G.add(H);
199                    return G; // since no threads are activated
200                }
201                if (debug) {
202                    logger.info("H = " + H);
203                }
204                if (H.length() > 0) {
205                    //l++;
206                    G.add(H);
207                    pairlist.put(H);
208                }
209            }
210        }
211        //logger.info("#sequential list = " + G.size());
212        G = minimalGB(G);
213        logger.info("" + pairlist);
214        //Collections.sort(G);
215        //Collections.reverse(G);
216        return G;
217    }
218
219
220    /**
221     * Minimal ordered Groebner basis.
222     * @param Gp a Groebner base.
223     * @return a reduced Groebner base of Gp.
224     */
225    @Override
226    public List<GenWordPolynomial<GenPolynomial<C>>> minimalGB(List<GenWordPolynomial<GenPolynomial<C>>> Gp) {
227        if (Gp == null || Gp.size() <= 1) {
228            return Gp;
229        }
230        // remove zero polynomials
231        List<GenWordPolynomial<GenPolynomial<C>>> G = new ArrayList<GenWordPolynomial<GenPolynomial<C>>>(
232                        Gp.size());
233        for (GenWordPolynomial<GenPolynomial<C>> a : Gp) {
234            if (a != null && !a.isZERO()) { // always true in GB()
235                // already positive a = a.abs();
236                G.add(a);
237            }
238        }
239        if (G.size() <= 1) {
240            return G;
241        }
242        // remove top reducible polynomials
243        GenWordPolynomial<GenPolynomial<C>> a;
244        List<GenWordPolynomial<GenPolynomial<C>>> F;
245        F = new ArrayList<GenWordPolynomial<GenPolynomial<C>>>(G.size());
246        while (G.size() > 0) {
247            a = G.remove(0);
248            if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) {
249                // drop polynomial 
250                if (debug) {
251                    System.out.println("dropped " + a);
252                    List<GenWordPolynomial<GenPolynomial<C>>> ff;
253                    ff = new ArrayList<GenWordPolynomial<GenPolynomial<C>>>(G);
254                    ff.addAll(F);
255                    a = redRec.normalformRecursive(ff, a);
256                    if (!a.isZERO()) {
257                        System.out.println("error, nf(a) " + a);
258                    }
259                }
260            } else {
261                F.add(a);
262            }
263        }
264        G = F;
265        if (G.size() <= 1) {
266            return G;
267        }
268        // reduce remaining polynomials
269        Collections.reverse(G); // important for lex GB
270        int len = G.size();
271        if (debug) {
272            System.out.println("#G " + len);
273            for (GenWordPolynomial<GenPolynomial<C>> aa : G) {
274                System.out.println("aa = " + aa.length() + ", lt = " + aa.getMap().keySet());
275            }
276        }
277        int i = 0;
278        while (i < len) {
279            a = G.remove(0);
280            if (debug) {
281                System.out.println("doing " + a.length() + ", lt = " + a.leadingWord());
282            }
283            a = redRec.normalformRecursive(G, a);
284            G.add(a); // adds as last
285            i++;
286        }
287        return G;
288    }
289
290
291    /**
292     * Wird Groebner base simple test.
293     * @param F recursive polynomial list.
294     * @return true, if F is a Groebner base, else false.
295     */
296    @Override
297    public boolean isGB(List<GenWordPolynomial<GenPolynomial<C>>> F) {
298        if (F == null || F.isEmpty()) {
299            return true;
300        }
301        GenWordPolynomial<GenPolynomial<C>> pi, pj, h;
302        List<GenWordPolynomial<GenPolynomial<C>>> S;
303        for (int i = 0; i < F.size(); i++) {
304            pi = F.get(i);
305            for (int j = 0; j < F.size(); j++) {
306                if (i == j) {
307                    continue;
308                }
309                pj = F.get(j);
310
311                S = red.SPolynomials(pi, pj);
312                if (S.isEmpty()) {
313                    continue;
314                }
315                for (GenWordPolynomial<GenPolynomial<C>> s : S) {
316                    //System.out.println("i, j = " + i + ", " + j); 
317                    h = redRec.normalformRecursive(F, s);
318                    if (!h.isZERO()) {
319                        logger.info("no GB: pi = " + pi + ", pj = " + pj);
320                        logger.info("s  = " + s + ", h = " + h);
321                        return false;
322                    }
323                }
324            }
325        }
326        return true;
327    }
328
329
330    /**
331     * GenWordPolynomial recursive coefficient content.
332     * @param P recursive GenWordPolynomial.
333     * @return cont(P).
334     */
335    public GenPolynomial<C> recursiveContent(GenWordPolynomial<GenPolynomial<C>> P) {
336        if (P == null) {
337            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
338        }
339        if (P.isZERO()) {
340            return P.ring.getZEROCoefficient();
341        }
342        GenPolynomial<C> d = null;
343        for (GenPolynomial<C> c : P.getMap().values()) {
344            //System.out.println("value c = " + c.leadingExpVector());
345            if (d == null) {
346                d = c;
347            } else {
348                d = engine.gcd(d, c);
349            }
350            if (d.isONE()) {
351                return d;
352            }
353        }
354        if (d.signum() < 0) {
355            d = d.negate();
356        }
357        return d;
358    }
359
360
361    /**
362     * GenWordPolynomial recursive coefficient primitive part.
363     * @param P recursive GenWordPolynomial.
364     * @return pp(P).
365     */
366    public GenWordPolynomial<GenPolynomial<C>> recursivePrimitivePart(GenWordPolynomial<GenPolynomial<C>> P) {
367        if (P == null) {
368            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
369        }
370        if (P.isZERO()) {
371            return P;
372        }
373        GenPolynomial<C> d = recursiveContent(P);
374        if (d.isONE()) {
375            return P;
376        }
377        //GenWordPolynomial<GenPolynomial<C>> pp = P.divide(d);
378        GenWordPolynomial<GenPolynomial<C>> pp = PolyUtil.<C> recursiveDivide(P, d);
379        if (debug) {
380            GenWordPolynomial<GenPolynomial<C>> p = pp.multiply(d);
381            if (!p.equals(P)) {
382                throw new ArithmeticException("pp(p)*cont(p) != p: ");
383            }
384        }
385        return pp;
386    }
387
388
389    /**
390     * List of GenWordPolynomial recursive coefficient primitive part.
391     * @param F list of recursive GenWordPolynomials.
392     * @return pp(F).
393     */
394    public List<GenWordPolynomial<GenPolynomial<C>>> recursivePrimitivePart(
395                    List<GenWordPolynomial<GenPolynomial<C>>> F) {
396        if (F == null || F.isEmpty()) {
397            return F;
398        }
399        List<GenWordPolynomial<GenPolynomial<C>>> Pp = new ArrayList<GenWordPolynomial<GenPolynomial<C>>>(
400                        F.size());
401        for (GenWordPolynomial<GenPolynomial<C>> f : F) {
402            GenWordPolynomial<GenPolynomial<C>> p = recursivePrimitivePart(f);
403            Pp.add(p);
404        }
405        return Pp;
406    }
407
408}