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