001/*
002 * $Id: SigReductionSeq.java 5869 2018-07-20 15:53:10Z kredel $
003 */
004
005package edu.jas.gb;
006
007
008import java.util.ArrayList;
009import java.util.LinkedList;
010import java.util.List;
011import java.util.Comparator;
012import java.util.stream.Collectors;
013import java.util.Map;
014
015import org.apache.logging.log4j.Logger;
016import org.apache.logging.log4j.LogManager; 
017
018import edu.jas.poly.ExpVector;
019import edu.jas.poly.GenPolynomial;
020import edu.jas.poly.GenPolynomialRing;
021import edu.jas.structure.RingElem;
022
023
024/**
025 * Polynomial SigReduction class. Implements common S-Polynomial, normalform
026 * with respect to signatures.
027 * @param <C> coefficient type
028 * @author Heinz Kredel
029 */
030
031public class SigReductionSeq<C extends RingElem<C>> implements SigReduction<C> {
032
033
034    private static final Logger logger = LogManager.getLogger(SigReductionSeq.class);
035
036
037    //private static final boolean debug = logger.isDebugEnabled();
038
039
040    final ReductionAbstract<C> red;
041
042
043    /**
044     * Constructor.
045     */
046    public SigReductionSeq() {
047        red = new ReductionSeq<C>();
048    }
049
050
051    /**
052     * S-Polynomial.
053     * @param A polynomial.
054     * @param B polynomial.
055     * @return spol(A,B) the S-polynomial of A and B.
056     */
057    public GenPolynomial<C> SPolynomial(SigPoly<C> A, SigPoly<C> B) {
058        GenPolynomial<C> s = red.SPolynomial(A.poly, B.poly);
059        return s;
060    }
061
062
063    /**
064     * S-Polynomial factors.
065     * @param A monic polynomial.
066     * @param B monic polynomial.
067     * @return exponent vectors [e,f] such that spol(A,B) = e*a - f*B.
068     */
069    public ExpVector[] SPolynomialExpVectorFactors(SigPoly<C> A, SigPoly<C> B) {
070        Map.Entry<ExpVector, C> ma = A.poly.leadingMonomial();
071        Map.Entry<ExpVector, C> mb = B.poly.leadingMonomial();
072        ExpVector e = ma.getKey();
073        ExpVector f = mb.getKey();
074        ExpVector g = e.lcm(f);
075        ExpVector e1 = g.subtract(e);
076        ExpVector f1 = g.subtract(f);
077        ExpVector[] F = new ExpVector[] { e1, f1 };
078        return F;
079    }
080
081
082    /**
083     * S-Polynomial half.
084     * @param A monic polynomial.
085     * @param B monic polynomial.
086     * @return e*A "half" of an S-polynomial such that spol(A,B) = e*A - f*B.
087     */
088    public GenPolynomial<C> SPolynomialHalf(SigPoly<C> A, SigPoly<C> B) {
089        Map.Entry<ExpVector, C> ma = A.poly.leadingMonomial();
090        Map.Entry<ExpVector, C> mb = B.poly.leadingMonomial();
091        ExpVector e = ma.getKey();
092        ExpVector f = mb.getKey();
093        ExpVector g = e.lcm(f);
094        ExpVector e1 = g.subtract(e);
095        GenPolynomial<C> F = A.poly.multiply(e1);
096        return F;
097    }
098
099
100    /**
101     * S-Polynomial polynomial factors.
102     * @param A monic polynomial.
103     * @param B monic polynomial.
104     * @return polynomials [e,f] such that spol(A,B) = e*a - f*B.
105     */
106    public GenPolynomial<C>[] SPolynomialFactors(SigPoly<C> A, SigPoly<C> B) {
107        ExpVector[] ev = SPolynomialExpVectorFactors(A, B);
108        GenPolynomial<C> e1 = A.poly.ring.valueOf(ev[0]);
109        GenPolynomial<C> f1 = A.poly.ring.valueOf(ev[1]);
110        @SuppressWarnings("unchecked")
111        GenPolynomial<C>[] F = new GenPolynomial[] { e1, f1 };
112        return F;
113    }
114
115
116    /**
117     * Is top reducible. Condition is lt(B) | lt(A) for some B in F or G.
118     * @param A polynomial.
119     * @param F polynomial list.
120     * @param G polynomial list.
121     * @return true if A is top reducible with respect to F and G.
122     */
123    public boolean isSigReducible(List<SigPoly<C>> F, List<SigPoly<C>> G, SigPoly<C> A) {
124        return !isSigNormalform(F, G, A);
125    }
126
127
128    /**
129     * Is in top normalform.
130     * @param A polynomial.
131     * @param F polynomial list.
132     * @param G polynomial list.
133     * @return true if A is in top normalform with respect to F and G.
134     */
135    public boolean isSigNormalform(List<SigPoly<C>> F, List<SigPoly<C>> G, SigPoly<C> A) {
136        if (F.isEmpty() && G.isEmpty()) {
137            return true;
138        }
139        if (A.poly.isZERO()) {
140            return true;
141        }
142        boolean mt = false;
143        for (ExpVector e : A.poly.getMap().keySet()) {
144            for (SigPoly<C> p : F) {
145                ExpVector f = p.poly.leadingExpVector();
146                mt = e.multipleOf(f);
147                if (mt) {
148                    return false;
149                }
150            }
151            for (SigPoly<C> p : G) {
152                if (p.poly.isZERO()) {
153                    continue;
154                }
155                ExpVector f = p.poly.leadingExpVector();
156                mt = e.multipleOf(f);
157                if (mt) {
158                    ExpVector g = e.subtract(f);
159                    GenPolynomial<C> sigma = p.sigma.multiply(g);
160                    if (sigma.leadingExpVector().compareTo(A.sigma.leadingExpVector()) < 0) {
161                        return false;
162                    }
163                    if (sigma.leadingExpVector().compareTo(A.sigma.leadingExpVector()) == 0
164                                    && sigma.leadingBaseCoefficient().compareTo(
165                                                    A.sigma.leadingBaseCoefficient()) != 0) {
166                        return false;
167                    }
168                }
169            }
170        }
171        return true;
172    }
173
174
175    /**
176     * Is sigma redundant.
177     * @param A polynomial.
178     * @param G polynomial list.
179     * @return true if A is sigma redundant with respect to G.
180     */
181    public boolean isSigRedundant(List<SigPoly<C>> G, SigPoly<C> A) {
182        if (G.isEmpty()) {
183            return false;
184        }
185        ExpVector e = A.sigma.leadingExpVector();
186        if (e == null) {
187            e = A.poly.ring.evzero;
188        }
189        for (SigPoly<C> p : G) {
190            if (p.sigma.isZERO()) {
191                continue;
192            }
193            ExpVector f = p.sigma.leadingExpVector();
194            if (f == null) { // does not happen
195                f = p.poly.ring.evzero;
196            }
197            boolean mt = e.multipleOf(f);
198            if (mt) {
199                ExpVector g = e.subtract(f);
200                ExpVector h = p.poly.leadingExpVector();
201                h = h.sum(g);
202                if (h.compareTo(A.poly.leadingExpVector()) == 0) {
203                    return true;
204                }
205            }
206        }
207        return false;
208    }
209
210
211    /**
212     * Is sigma redundant, alternative algorithm.
213     * @param A polynomial.
214     * @param G polynomial list.
215     * @return true if A is sigma redundant per alternative algorithm with
216     *         respect to G.
217     */
218    public boolean isSigRedundantAlt(List<SigPoly<C>> G, SigPoly<C> A) {
219        if (G.isEmpty()) {
220            return false;
221        }
222        ExpVector e = A.sigma.leadingExpVector();
223        if (e == null) {
224            e = A.poly.ring.evzero;
225        }
226        for (SigPoly<C> p : G) {
227            if (p.sigma.isZERO()) {
228                continue;
229            }
230            ExpVector f = p.sigma.leadingExpVector();
231            if (f == null) { // does not happen
232                f = p.poly.ring.evzero;
233            }
234            boolean mt = e.multipleOf(f);
235            if (mt) {
236                if (p.poly.isZERO()) {
237                    continue;
238                }
239                ExpVector h = p.poly.leadingExpVector();
240                ExpVector g = A.poly.leadingExpVector();
241                if (g.multipleOf(h)) {
242                    return true;
243                }
244            }
245        }
246        return false;
247    }
248
249
250    /**
251     * Top normalform.
252     * @param A polynomial.
253     * @param F polynomial list.
254     * @param G polynomial list.
255     * @return nf(A) with respect to F and G.
256     */
257    public SigPoly<C> sigNormalform(List<GenPolynomial<C>> F, List<SigPoly<C>> G, SigPoly<C> A) {
258        if (F.isEmpty() && G.isEmpty()) {
259            return A;
260        }
261        if (A.poly.isZERO()) {
262            return A;
263        }
264        List<GenPolynomial<C>> ff = F; //polys(F);
265        GenPolynomial<C> a = A.poly;
266        GenPolynomial<C> sigma = A.sigma;
267        GenPolynomialRing<C> ring = a.ring;
268        boolean reduced = true;
269        while (!a.isZERO() && reduced) {
270            reduced = false;
271            a = red.normalform(ff, a);
272            if (a.isZERO()) {
273                continue;
274            }
275            ExpVector e = a.leadingExpVector();
276            for (SigPoly<C> p : G) {
277                if (p.poly.isZERO()) {
278                    continue;
279                }
280                ExpVector f = p.poly.leadingExpVector();
281                boolean mt = e.multipleOf(f);
282                if (mt) {
283                    ExpVector g = e.subtract(f);
284                    C sc = a.leadingBaseCoefficient().divide(p.poly.leadingBaseCoefficient());
285                    GenPolynomial<C> sigup = p.sigma.multiply(sc, g);
286                    ExpVector se = sigma.leadingExpVector();
287                    if (se == null) {
288                        se = ring.evzero;
289                    }
290                    ExpVector sp = sigup.leadingExpVector();
291                    if (sp == null) {
292                        sp = ring.evzero;
293                    }
294                    //logger.info("sigup, sigma  = " + sigup + ", " + sigma);
295                    boolean sigeq = (sigup.compareTo(sigma) < 0)
296                                    || ((sp.compareTo(se) == 0 && (sigup.leadingBaseCoefficient().compareTo(
297                                                    sigma.leadingBaseCoefficient()) != 0)));
298                    //logger.info("sigup < sigma = " + sigup.compareTo(sigma));
299                    if (sigeq) {
300                        reduced = true;
301                        a = a.subtractMultiple(sc, g, p.poly);
302                        if (sp.invGradCompareTo(se) == 0) {
303                            sigma = sigma.subtract(sigup);
304                        }
305                        if (a.isZERO()) {
306                            break;
307                        }
308                        e = a.leadingExpVector();
309                    } else {
310                        //logger.info("not reduced: a = " + a + ", p = " + p.poly);
311                    }
312                }
313            }
314        }
315        if (!a.isZERO()) {
316            C ac = a.leadingBaseCoefficient();
317            if (!ac.isONE()) {
318                ac = ac.inverse();
319                a = a.multiply(ac);
320                sigma = sigma.multiply(ac);
321            }
322        }
323        return new SigPoly<C>(sigma, a);
324    }
325
326
327    /**
328     * Top semi-complete normalform.
329     * @param A polynomial.
330     * @param F polynomial list.
331     * @param G polynomial list.
332     * @return nf(A) with respect to F and G.
333     */
334    public SigPoly<C> sigSemiNormalform(List<GenPolynomial<C>> F, List<SigPoly<C>> G, SigPoly<C> A) {
335        if (F.isEmpty() && G.isEmpty()) {
336            return A;
337        }
338        if (A.poly.isZERO()) {
339            return A;
340        }
341        List<GenPolynomial<C>> ff = F; //polys(F);
342        GenPolynomial<C> a = A.poly;
343        GenPolynomial<C> sigma = A.sigma;
344        ExpVector esig = sigma.leadingExpVector();
345        if (esig == null) {
346            logger.info("esig = null");
347            //esig = a.ring.evzero;
348        }
349        //GenPolynomialRing<C> ring = a.ring;
350        boolean reduced = true;
351        while (!a.isZERO() && reduced) {
352            reduced = false;
353            a = red.normalform(ff, a);
354            if (a.isZERO()) {
355                continue;
356            }
357            ExpVector e = a.leadingExpVector();
358            for (SigPoly<C> p : G) {
359                if (p.poly.isZERO()) {
360                    continue;
361                }
362                ExpVector f = p.poly.leadingExpVector();
363                boolean mt = e.multipleOf(f);
364                if (mt) {
365                    ExpVector g = e.subtract(f);
366                    C sc = a.leadingBaseCoefficient().divide(p.poly.leadingBaseCoefficient());
367                    GenPolynomial<C> sigup = p.sigma.multiply(sc, g);
368                    ExpVector eup = sigup.leadingExpVector();
369                    if (eup == null) {
370                        logger.info("eup = null");
371                        //eup = a.ring.evzero;
372                        throw new IllegalArgumentException("eup == null: " + sigup);
373                    }
374
375                    //wrong: boolean sigeq = (sigup.compareTo(sigma) < 0);
376                    boolean sigeq = (eup.compareTo(esig) < 0);
377                    if (sigeq) {
378                        //logger.info("reduced: sigup = " + sigup + ", sigma = " + sigma);
379                        reduced = true;
380                        a = a.subtractMultiple(sc, g, p.poly);
381                        if (a.isZERO()) {
382                            break;
383                        }
384                        e = a.leadingExpVector();
385                    } else {
386                        //logger.info("not reduced: a = " + a + ", p = " + p.poly);
387                    }
388                }
389            }
390        }
391        if (!a.isZERO()) {
392            C ac = a.leadingBaseCoefficient();
393            if (!ac.isONE()) {
394                ac = ac.inverse();
395                a = a.multiply(ac);
396            }
397        }
398        return new SigPoly<C>(sigma, a);
399    }
400
401
402    /**
403     * Select polynomials.
404     * @param F list of signature polynomials.
405     * @return the polynomials in F.
406     */
407    public List<GenPolynomial<C>> polys(List<SigPoly<C>> F) {
408        List<GenPolynomial<C>> ff = new ArrayList<GenPolynomial<C>>();
409        for (SigPoly<C> p : F) {
410            if (!p.poly.isZERO()) {
411                ff.add(p.poly);
412            }
413        }
414        return ff;
415    }
416
417
418    /**
419     * Select signatures.
420     * @param F list of signature polynomials.
421     * @return the signatures in F.
422     */
423    public List<GenPolynomial<C>> sigmas(List<SigPair<C>> F) {
424        List<GenPolynomial<C>> ff = new ArrayList<GenPolynomial<C>>();
425        for (SigPair<C> p : F) {
426            ff.add(p.sigma);
427        }
428        return ff;
429    }
430
431
432    /**
433     * Minimal degree of signatures.
434     * @param F list of signature polynomials.
435     * @return the minimal degree of the signatures in F.
436     */
437    public long minimalSigDegree(List<SigPair<C>> F) {
438        long deg = Long.MAX_VALUE;
439        for (SigPair<C> p : F) {
440            //long d = p.sigma.totalDegree();
441            long d = p.sigma.degree();
442            if (d < deg) {
443                deg = d;
444            }
445        }
446        return deg;
447    }
448
449
450    /**
451     * Select signature polynomials of minimal degree and non minimal degree.
452     * @param F list of signature polynomials.
453     * @return [m,p] where m is the list of signature polynomials of F of
454     *         minimal degree and p contains the rest of the signature
455     *         polynomials with non minimal degree.
456     */
457    public List<SigPair<C>>[] minDegSubset(List<SigPair<C>> F) {
458        long mdeg = minimalSigDegree(F);
459        List<SigPair<C>> ff = new ArrayList<SigPair<C>>();
460        List<SigPair<C>> pp = new ArrayList<SigPair<C>>();
461        for (SigPair<C> p : F) {
462            //if (p.sigma.totalDegree() == mdeg) {
463            if (p.sigma.degree() == mdeg) {
464                ff.add(p);
465            } else {
466                pp.add(p);
467            }
468        }
469        @SuppressWarnings("unchecked")
470        List<SigPair<C>>[] P = new List[2];
471        P[0] = ff;
472        P[1] = pp;
473        return P;
474    }
475
476
477    /**
478     * Sort signature polynomials according to the degree its signatures.
479     * @param F list of signature polynomials.
480     * @return list of signature polynomials sorted by degree of sigma.
481     */
482    public List<SigPair<C>> sortSigma(List<SigPair<C>> F) {
483        //Comparator<SigPair<C>> sigcmp = Comparator.comparing(SigPair::getSigma::degree);
484        Comparator<SigPair<C>> sigcmp = Comparator.comparingLong(SigPair::getSigmaDegree);
485        List<SigPair<C>> ff = F.stream().sorted(sigcmp).collect(Collectors.toList());
486        return ff;
487    }
488}