001/*
002 * $Id: SolvableSyzygySeq.java 5870 2018-07-20 15:56:23Z kredel $
003 */
004
005package edu.jas.gbufd;
006
007
008import java.util.ArrayList;
009import java.util.Arrays;
010import java.util.Iterator;
011import java.util.List;
012
013import org.apache.logging.log4j.Logger;
014import org.apache.logging.log4j.LogManager; 
015
016import edu.jas.gb.SolvableExtendedGB;
017import edu.jas.gb.SolvableGroebnerBase;
018import edu.jas.poly.GenPolynomial;
019import edu.jas.poly.GenSolvablePolynomial;
020import edu.jas.poly.GenSolvablePolynomialRing;
021import edu.jas.poly.ModuleList;
022import edu.jas.poly.PolynomialList;
023import edu.jas.structure.GcdRingElem;
024import edu.jas.structure.RingFactory;
025
026
027/**
028 * Syzygy sequential class for solvable polynomials. Implements Syzygy
029 * computations and tests with Groebner bases.
030 * @param <C> coefficient type
031 * @author Heinz Kredel
032 */
033
034public class SolvableSyzygySeq<C extends GcdRingElem<C>> extends SolvableSyzygyAbstract<C> {
035
036
037    private static final Logger logger = LogManager.getLogger(SolvableSyzygySeq.class);
038
039
040    private static final boolean debug = logger.isDebugEnabled();
041
042
043    private static boolean assertEnabled = false;
044
045
046    static {
047        assert assertEnabled = true; // official hack to check assertions enabled
048    }
049
050
051    /**
052     * Groebner basis engine.
053     */
054    protected SolvableGroebnerBase<C> sbb;
055
056
057    /*
058     * Module Groebner basis engine.
059    //protected ModSolvableGroebnerBase<C> msbb;
060     */
061
062
063    /**
064     * Constructor.
065     * @param cf coefficient ring.
066     */
067    public SolvableSyzygySeq(RingFactory<C> cf) {
068        sbb = SGBFactory.getImplementation(cf);
069        //msbb = new ModSolvableGroebnerBaseSeq<C>(cf);
070    }
071
072
073    /**
074     * Resolution of a module. Only with direct GBs.
075     * @param M a module list of a Groebner basis.
076     * @return a resolution of M.
077     */
078    public List<SolvResPart<C>> resolution(ModuleList<C> M) {
079        List<SolvResPart<C>> R = new ArrayList<SolvResPart<C>>();
080        ModuleList<C> MM = M;
081        ModuleList<C> GM;
082        ModuleList<C> Z;
083        while (true) {
084            GM = sbb.leftGB(MM);
085            Z = leftZeroRelations(GM);
086            R.add(new SolvResPart<C>(MM, GM, Z));
087            if (Z == null || Z.list == null || Z.list.size() == 0) {
088                break;
089            }
090            MM = Z;
091        }
092        return R;
093    }
094
095
096    /**
097     * Resolution of a polynomial list. Only with direct GBs.
098     * @param F a polynomial list of a Groebner basis.
099     * @return a resolution of F.
100     */
101    @SuppressWarnings("unchecked")
102    public List/*<SolvResPart<C>|SolvResPolPart<C>>*/resolution(PolynomialList<C> F) {
103        List<List<GenSolvablePolynomial<C>>> Z;
104        ModuleList<C> Zm;
105        List<GenSolvablePolynomial<C>> G;
106        PolynomialList<C> Gl;
107
108        G = sbb.leftGB(F.castToSolvableList());
109        Z = leftZeroRelations(G);
110        Gl = new PolynomialList<C>((GenSolvablePolynomialRing<C>) F.ring, G);
111        Zm = new ModuleList<C>((GenSolvablePolynomialRing<C>) F.ring, Z);
112
113        List R = resolution(Zm);
114        R.add(0, new SolvResPolPart<C>(F, Gl, Zm));
115        return R;
116    }
117
118
119    /**
120     * Resolution of a module.
121     * @param M a module list of an arbitrary basis.
122     * @return a resolution of M.
123     */
124    public List<SolvResPart<C>> resolutionArbitrary(ModuleList<C> M) {
125        List<SolvResPart<C>> R = new ArrayList<SolvResPart<C>>();
126        ModuleList<C> MM = M;
127        ModuleList<C> GM = null;
128        ModuleList<C> Z;
129        while (true) {
130            //GM = sbb.leftGB(MM);
131            Z = leftZeroRelationsArbitrary(MM);
132            R.add(new SolvResPart<C>(MM, GM, Z));
133            if (Z == null || Z.list == null || Z.list.size() == 0) {
134                break;
135            }
136            MM = Z;
137        }
138        return R;
139    }
140
141
142    /**
143     * Resolution of a polynomial list.
144     * @param F a polynomial list of an arbitrary basis.
145     * @return a resolution of F.
146     */
147    @SuppressWarnings("unchecked")
148    public List/*<SolvResPart<C>|SolvResPolPart<C>>*/resolutionArbitrary(PolynomialList<C> F) {
149        List<List<GenSolvablePolynomial<C>>> Z;
150        ModuleList<C> Zm;
151        PolynomialList<C> Gl = null;
152        //List<GenSolvablePolynomial<C>> G = sbb.leftGB( F.castToSolvableList() );
153        //Gl = new PolynomialList<C>((GenSolvablePolynomialRing<C>)F.ring, G);
154        Z = leftZeroRelationsArbitrary(F.castToSolvableList());
155        Zm = new ModuleList<C>((GenSolvablePolynomialRing<C>) F.ring, Z);
156
157        List R = resolutionArbitrary(Zm);
158        R.add(0, new SolvResPolPart<C>(F, Gl, Zm));
159        return R;
160    }
161
162
163    /**
164     * Left syzygy module from arbitrary base.
165     * @param modv number of module variables.
166     * @param F a solvable polynomial list.
167     * @return syz(F), a basis for the module of left syzygies for F.
168     */
169    @SuppressWarnings("unchecked")
170    public List<List<GenSolvablePolynomial<C>>> leftZeroRelationsArbitrary(int modv,
171                    List<GenSolvablePolynomial<C>> F) {
172        if (F == null) {
173            return null; //leftZeroRelations( modv, F );
174        }
175        if (F.size() <= 1) {
176            return leftZeroRelations(modv, F);
177        }
178        final int lenf = F.size();
179        SolvableExtendedGB<C> exgb = sbb.extLeftGB(modv, F);
180        if (debug) {
181            logger.info("exgb = " + exgb);
182        }
183        if (assertEnabled) {
184            logger.info("check1 exgb start");
185            if (!sbb.isLeftReductionMatrix(exgb)) {
186                logger.error("is reduction matrix ? false");
187            }
188            logger.info("check1 exgb end");
189        }
190        List<GenSolvablePolynomial<C>> G = exgb.G;
191        List<List<GenSolvablePolynomial<C>>> G2F = exgb.G2F;
192        List<List<GenSolvablePolynomial<C>>> F2G = exgb.F2G;
193
194        List<List<GenSolvablePolynomial<C>>> sg = leftZeroRelations(modv, G);
195        GenSolvablePolynomialRing<C> ring = G.get(0).ring;
196        ModuleList<C> S = new ModuleList<C>(ring, sg);
197        if (debug) {
198            logger.info("syz = " + S);
199        }
200        if (assertEnabled) {
201            logger.info("check2 left syz start");
202            if (!isLeftZeroRelation(sg, G)) {
203                logger.error("is syzygy ? false");
204            }
205            logger.info("check2 left syz end");
206        }
207
208        List<List<GenSolvablePolynomial<C>>> sf;
209        sf = new ArrayList<List<GenSolvablePolynomial<C>>>(sg.size());
210        //List<GenPolynomial<C>> row;
211
212        for (List<GenSolvablePolynomial<C>> r : sg) {
213            Iterator<GenSolvablePolynomial<C>> it = r.iterator();
214            Iterator<List<GenSolvablePolynomial<C>>> jt = G2F.iterator();
215
216            List<GenSolvablePolynomial<C>> rf;
217            rf = new ArrayList<GenSolvablePolynomial<C>>(lenf);
218            for (int m = 0; m < lenf; m++) {
219                rf.add(ring.getZERO());
220            }
221            while (it.hasNext() && jt.hasNext()) {
222                GenSolvablePolynomial<C> si = it.next();
223                List<GenSolvablePolynomial<C>> ai = jt.next();
224                //System.out.println("si = " + si);
225                //System.out.println("ai = " + ai);
226                if (si == null || ai == null) {
227                    continue;
228                }
229                // pi has wrong type:
230                List<GenPolynomial<C>> pi = blas.scalarProduct(si, PolynomialList.<C> castToList(ai));
231                //System.out.println("pi = " + pi);
232                rf = PolynomialList.<C> castToSolvableList(blas.vectorAdd(PolynomialList.<C> castToList(rf),
233                                pi));
234            }
235            if (it.hasNext() || jt.hasNext()) {
236                logger.error("leftZeroRelationsArbitrary wrong sizes");
237            }
238            //System.out.println("\nrf = " + rf + "\n");
239            sf.add(rf);
240        }
241        if (assertEnabled) {
242            logger.info("check3 left syz start");
243            if (!isLeftZeroRelation(sf, F)) {
244                logger.error("is partial syz sf ? false");
245            }
246            logger.info("check3 left syz end");
247        }
248
249        List<List<GenSolvablePolynomial<C>>> M;
250        M = new ArrayList<List<GenSolvablePolynomial<C>>>(lenf);
251        for (List<GenSolvablePolynomial<C>> r : F2G) {
252            Iterator<GenSolvablePolynomial<C>> it = r.iterator();
253            Iterator<List<GenSolvablePolynomial<C>>> jt = G2F.iterator();
254
255            List<GenSolvablePolynomial<C>> rf;
256            rf = new ArrayList<GenSolvablePolynomial<C>>(lenf);
257            for (int m = 0; m < lenf; m++) {
258                rf.add(ring.getZERO());
259            }
260            while (it.hasNext() && jt.hasNext()) {
261                GenSolvablePolynomial<C> si = it.next();
262                List<GenSolvablePolynomial<C>> ai = jt.next();
263                //System.out.println("si = " + si);
264                //System.out.println("ai = " + ai);
265                if (si == null || ai == null) {
266                    continue;
267                }
268                //pi has wrong type, should be: List<GenSolvablePolynomial<C>>
269                List<GenPolynomial<C>> pi = blas.scalarProduct(si, PolynomialList.<C> castToList(ai));
270                //System.out.println("pi = " + pi);
271                rf = PolynomialList.<C> castToSolvableList(blas.vectorAdd(PolynomialList.<C> castToList(rf),
272                                pi));
273            }
274            if (it.hasNext() || jt.hasNext()) {
275                logger.error("zeroRelationsArbitrary wrong sizes");
276            }
277            //System.out.println("\nMg Mf = " + rf + "\n");
278            M.add(rf);
279        }
280        //ModuleList<C> ML = new ModuleList<C>( ring, M );
281        //System.out.println("syz ML = " + ML);
282        // debug only:
283        //List<GenSolvablePolynomial<C>> F2 = new ArrayList<GenSolvablePolynomial<C>>( F.size() );
284        /* not true in general
285        List<GenPolynomial<C>> Fp = PolynomialList.<C>castToList(F);
286        for ( List<GenSolvablePolynomial<C>> rr: M ) {
287            GenSolvablePolynomial<C> rrg = PolynomialList.<C>castToSolvableList(blas.scalarProduct(Fp,PolynomialList.<C>castToList(rr)));
288            F2.add( rrg );
289        }
290        PolynomialList<C> pF = new PolynomialList<C>( ring, F );
291        PolynomialList<C> pF2 = new PolynomialList<C>( ring, F2 );
292        if ( ! pF.equals( pF2 ) ) {
293           logger.error("is FAB = F ? false");
294           //System.out.println("pF  = " + pF.list.size());
295           //System.out.println("pF2 = " + pF2.list.size());
296        }
297        */
298        int sflen = sf.size();
299        List<List<GenSolvablePolynomial<C>>> M2;
300        M2 = new ArrayList<List<GenSolvablePolynomial<C>>>(lenf);
301        int i = 0;
302        for (List<GenSolvablePolynomial<C>> ri : M) {
303            List<GenSolvablePolynomial<C>> r2i;
304            r2i = new ArrayList<GenSolvablePolynomial<C>>(ri.size());
305            int j = 0;
306            for (GenSolvablePolynomial<C> rij : ri) {
307                GenSolvablePolynomial<C> p = null;
308                if (i == j) {
309                    p = (GenSolvablePolynomial<C>) ring.getONE().subtract(rij);
310                } else {
311                    if (rij != null) {
312                        p = (GenSolvablePolynomial<C>) rij.negate();
313                    }
314                }
315                r2i.add(p);
316                j++;
317            }
318            M2.add(r2i);
319            if (!blas.isZero(PolynomialList.<C> castToList(r2i))) {
320                sf.add(r2i);
321            }
322            i++;
323        }
324        ModuleList<C> M2L = new ModuleList<C>(ring, M2);
325        if (debug) {
326            logger.debug("syz M2L = " + M2L);
327        }
328
329        if (debug) {
330            ModuleList<C> SF = new ModuleList<C>(ring, sf);
331            logger.debug("syz sf = " + SF);
332            logger.debug("#syz " + sflen + ", " + sf.size());
333        }
334        if (assertEnabled) {
335            logger.info("check4 left syz start");
336            if (!isLeftZeroRelation(sf, F)) {
337                logger.error("is syz sf ? false");
338            }
339            logger.info("check4 left syz end");
340        }
341        return sf;
342    }
343
344
345    /**
346     * Left Ore condition. Generators for the left Ore condition of two solvable
347     * polynomials.
348     * @param a solvable polynomial
349     * @param b solvable polynomial
350     * @return [p,q] with p*a = q*b
351     */
352    @SuppressWarnings({ "cast", "unchecked" })
353    public GenSolvablePolynomial<C>[] leftOreCond(GenSolvablePolynomial<C> a, GenSolvablePolynomial<C> b) {
354        if (a == null || a.isZERO() || b == null || b.isZERO()) {
355            throw new IllegalArgumentException("a and b must be non zero");
356        }
357        GenSolvablePolynomialRing<C> pfac = a.ring;
358        GenSolvablePolynomial<C>[] oc = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2];
359        if (a.equals(b)) {
360            oc[0] = pfac.getONE();
361            oc[1] = pfac.getONE();
362            return oc;
363        }
364        if (a.isConstant()) {
365            if (pfac.coFac.isCommutative()) { // ??
366                oc[0] = b;
367                oc[1] = a;
368                return oc;
369            }
370            oc[1] = pfac.getONE();
371            C c = a.leadingBaseCoefficient().inverse();
372            oc[0] = b.multiply(c);
373            return oc;
374        }
375        if (b.isConstant()) {
376            if (pfac.coFac.isCommutative()) { // ??
377                oc[0] = b;
378                oc[1] = a;
379                return oc;
380            }
381            oc[0] = pfac.getONE();
382            C c = b.leadingBaseCoefficient().inverse();
383            oc[1] = a.multiply(c);
384            return oc;
385        }
386        logger.info("computing left Ore condition: " + a + ", " + b);
387        List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(2);
388        F.add(a);
389        F.add(b);
390        List<List<GenSolvablePolynomial<C>>> Gz = leftZeroRelationsArbitrary(F);
391        /*
392        if (Gz.size() < 0) { // always false
393            //System.out.println("Gz = " + Gz);
394            ModuleList<C> M = new ModuleList<C>(pfac, Gz);
395            ModuleList<C> GM = sbb.leftGB(M);
396            //System.out.println("GM = " + GM);
397            Gz = GM.castToSolvableList();
398        }
399        */
400        List<GenSolvablePolynomial<C>> G1 = null;
401        GenSolvablePolynomial<C> g1 = null;
402        for (List<GenSolvablePolynomial<C>> Gi : Gz) {
403            //System.out.println("Gi = " + Gi);
404            if (Gi.get(0).isZERO()) {
405                continue;
406            }
407            if (G1 == null) {
408                G1 = Gi;
409            }
410            if (g1 == null) {
411                g1 = G1.get(0);
412            } else if (g1.compareTo(Gi.get(0)) > 0) { //g1.degree() > Gi.get(0).degree() 
413                G1 = Gi;
414                g1 = G1.get(0);
415            }
416        }
417        oc[0] = g1; //G1.get(0);
418        oc[1] = (GenSolvablePolynomial<C>) G1.get(1).negate();
419        //logger.info("Ore multiple: " + oc[0].multiply(a) + ", " + Arrays.toString(oc));
420        return oc;
421    }
422
423
424    /**
425     * Right Ore condition. Generators for the right Ore condition of two
426     * solvable polynomials.
427     * @param a solvable polynomial
428     * @param b solvable polynomial
429     * @return [p,q] with a*p = b*q
430     */
431    @SuppressWarnings({ "cast", "unchecked" })
432    public GenSolvablePolynomial<C>[] rightOreCond(GenSolvablePolynomial<C> a, GenSolvablePolynomial<C> b) {
433        if (a == null || a.isZERO() || b == null || b.isZERO()) {
434            throw new IllegalArgumentException("a and b must be non zero");
435        }
436        GenSolvablePolynomialRing<C> pfac = a.ring;
437        GenSolvablePolynomial<C>[] oc = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2];
438        if (a.equals(b)) {
439            oc[0] = pfac.getONE();
440            oc[1] = pfac.getONE();
441            return oc;
442        }
443        if (a.isConstant()) {
444            if (pfac.coFac.isCommutative()) { // ??
445                oc[0] = b;
446                oc[1] = a;
447                return oc;
448            }
449            oc[1] = pfac.getONE();
450            C c = a.leadingBaseCoefficient().inverse();
451            oc[0] = b.multiply(c);
452            return oc;
453        }
454        if (b.isConstant()) {
455            if (pfac.coFac.isCommutative()) { // ??
456                oc[0] = b;
457                oc[1] = a;
458                return oc;
459            }
460            oc[0] = pfac.getONE();
461            C c = b.leadingBaseCoefficient().inverse();
462            oc[1] = a.multiply(c);
463            return oc;
464        }
465        logger.info("computing right Ore condition: " + a + ", " + b);
466        List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(2);
467        F.add(a);
468        F.add(b);
469        List<List<GenSolvablePolynomial<C>>> Gz = rightZeroRelationsArbitrary(F);
470        List<GenSolvablePolynomial<C>> G1 = null;
471        GenSolvablePolynomial<C> g1 = null;
472        for (List<GenSolvablePolynomial<C>> Gi : Gz) {
473            if (Gi.get(0).isZERO()) {
474                continue;
475            }
476            if (G1 == null) {
477                G1 = Gi;
478            }
479            if (g1 == null) {
480                g1 = G1.get(0);
481            } else if (g1.compareTo(Gi.get(0)) > 0) {
482                G1 = Gi;
483                g1 = G1.get(0);
484            }
485        }
486        oc[0] = G1.get(0);
487        oc[1] = (GenSolvablePolynomial<C>) G1.get(1).negate();
488        //logger.info("Ore multiple: " + a.multiply(oc[0]) + ", " + Arrays.toString(oc));
489        return oc;
490    }
491
492
493    /**
494     * Left simplifier. Method of Apel &amp; Lassner (1987).
495     * @param a solvable polynomial
496     * @param b solvable polynomial
497     * @return [p,q] with a/b = p/q and q is minimal and monic
498     */
499    @Override
500    @SuppressWarnings({ "unchecked" })
501    public GenSolvablePolynomial<C>[] leftSimplifier(GenSolvablePolynomial<C> a, GenSolvablePolynomial<C> b) {
502        if (a == null || a.isZERO() || b == null || b.isZERO()) {
503            throw new IllegalArgumentException("a and b must be non zero");
504        }
505        GenSolvablePolynomial<C>[] oc = null;
506        if (a.isConstant() || b.isConstant()) {
507            oc = new GenSolvablePolynomial[] { a, b };
508            return oc;
509        }
510        if (a.totalDegree() > 3 || b.totalDegree() > 3) { // how avoid too long running GBs ?
511            //if (a.totalDegree() + b.totalDegree() > 6) { 
512            // && a.length() < 10 && b.length() < 10
513            logger.info("skipping simplifier GB computation: degs = " + a.totalDegree() + ", " + b.totalDegree());
514            oc = new GenSolvablePolynomial[] { a, b };
515            return oc;
516        }
517        //GenSolvablePolynomialRing<C> pfac = a.ring;
518        oc = rightOreCond(a, b);
519        logger.info("oc = " + Arrays.toString(oc)); // + ", a = " + a + ", b = " + b);
520        List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(oc.length);
521        // opposite order and undo negation
522        F.add((GenSolvablePolynomial<C>) oc[1].negate());
523        F.add(oc[0]);
524        //logger.info("F = " + F);
525        List<List<GenSolvablePolynomial<C>>> Gz = leftZeroRelationsArbitrary(F);
526        //logger.info("Gz: " + Gz);
527        List<GenSolvablePolynomial<C>> G1 = new ArrayList<GenSolvablePolynomial<C>>(Gz.size());
528        List<GenSolvablePolynomial<C>> G2 = new ArrayList<GenSolvablePolynomial<C>>(Gz.size());
529        for (List<GenSolvablePolynomial<C>> ll : Gz) {
530            if (!ll.get(0).isZERO()) { // && !ll.get(1).isZERO()
531                G1.add(ll.get(0)); // denominators
532                G2.add(ll.get(1)); // numerators
533            }
534        }
535        logger.info("G1(den): " + G1 + ", G2(num): " + G2);
536        SolvableExtendedGB<C> exgb = sbb.extLeftGB(G1);
537        logger.info("exgb.F: " + exgb.F + ", exgb.G: " + exgb.G);
538        List<GenSolvablePolynomial<C>> G = exgb.G;
539        int m = 0;
540        GenSolvablePolynomial<C> min = null;
541        for (int i = 0; i < G.size(); i++) {
542            if (min == null) {
543                min = G.get(i);
544                m = i;
545            } else if (min.compareTo(G.get(i)) > 0) {
546                min = G.get(i);
547                m = i;
548            }
549        }
550        //wrong: blas.scalarProduct(G2,exgb.G2F.get(m));
551        GenSolvablePolynomial<C> min2 = (GenSolvablePolynomial<C>) blas.scalarProduct(
552                        PolynomialList.<C> castToList(exgb.G2F.get(m)), PolynomialList.<C> castToList(G2));
553        logger.info("min(den): " + min + ", min(num): " + min2 + ", m = " + m + ", " + exgb.G2F.get(m));
554        // opposite order
555        GenSolvablePolynomial<C> n = min2; // nominator
556        GenSolvablePolynomial<C> d = min; // denominator
557        // normalize
558        if (d.signum() < 0) {
559            n = (GenSolvablePolynomial<C>) n.negate();
560            d = (GenSolvablePolynomial<C>) d.negate();
561        }
562        C lc = d.leadingBaseCoefficient();
563        if (!lc.isONE() && lc.isUnit()) {
564            lc = lc.inverse();
565            n = n.multiplyLeft(lc);
566            d = d.multiplyLeft(lc);
567        }
568        if (debug) {
569            int t = compare(a, b, n, d);
570            if (t != 0) {
571                oc[0] = a; // nominator
572                oc[1] = b; // denominator
573                throw new RuntimeException("simp wrong, giving up: t = " + t);
574                //logger.error("simp wrong, giving up: t = " + t);
575                //return oc;
576            }
577        }
578        oc[0] = n; // nominator
579        oc[1] = d; // denominator
580        return oc;
581    }
582
583}