001/*
002 * $Id: GroebnerBasePartial.java 5870 2018-07-20 15:56:23Z 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.GroebnerBaseAbstract;
016import edu.jas.gb.GroebnerBaseSeq;
017import edu.jas.poly.GenPolynomial;
018import edu.jas.poly.GenPolynomialRing;
019import edu.jas.poly.OptimizedPolynomialList;
020import edu.jas.poly.PolyUtil;
021import edu.jas.poly.TermOrder;
022import edu.jas.poly.TermOrderOptimization;
023import edu.jas.structure.GcdRingElem;
024import edu.jas.structure.RingFactory;
025
026
027/**
028 * Partial Groebner Bases for subsets of variables. Let <code>pvars</code> be a
029 * subset of variables <code>vars</code> of the polynomial ring K[vars]. Methods
030 * compute Groebner bases with coefficients from K[vars \ pvars] in the
031 * polynomial ring K[vars \ pvars][pvars].
032 * @param <C> coefficient type
033 * @author Heinz Kredel
034 */
035
036public class GroebnerBasePartial<C extends GcdRingElem<C>> extends GroebnerBaseAbstract<C> {
037
038
039    private static final Logger logger = LogManager.getLogger(GroebnerBasePartial.class);
040
041
042    //private static final boolean debug = logger.isDebugEnabled();
043
044
045    /**
046     * Backing Groebner base engine.
047     */
048    protected GroebnerBaseAbstract<C> bb;
049
050
051    /**
052     * Backing recursive Groebner base engine.
053     */
054    protected GroebnerBaseAbstract<GenPolynomial<C>> rbb; // can be null
055
056
057    /**
058     * Constructor.
059     */
060    public GroebnerBasePartial() {
061        this(new GroebnerBaseSeq<C>(), null);
062    }
063
064
065    /**
066     * Constructor.
067     * @param rf coefficient ring factory.
068     */
069    public GroebnerBasePartial(RingFactory<GenPolynomial<C>> rf) {
070        this(new GroebnerBaseSeq<C>(), new GroebnerBasePseudoRecSeq<C>(rf));
071    }
072
073
074    /**
075     * Constructor.
076     * @param bb Groebner base engine
077     * @param rbb recursive Groebner base engine
078     */
079    public GroebnerBasePartial(GroebnerBaseAbstract<C> bb, GroebnerBaseAbstract<GenPolynomial<C>> rbb) {
080        super();
081        this.bb = bb;
082        this.rbb = rbb;
083        //if (rbb == null) {
084            //logger.warn("no recursive GB given");
085        //}
086    }
087
088
089    /**
090     * Groebner base using pairlist class.
091     * @param modv module variable number.
092     * @param F polynomial list.
093     * @return GB(F) a Groebner base of F.
094     */
095    public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) {
096        return bb.GB(modv, F);
097    }
098
099
100    /**
101     * Groebner base test.
102     * @param F polynomial list.
103     * @return true, if F is a partial Groebner base, else false.
104     */
105    public boolean isGBrec(List<GenPolynomial<GenPolynomial<C>>> F) {
106        return isGBrec(0, F);
107    }
108
109
110    /**
111     * Groebner base test.
112     * @param modv module variable number.
113     * @param F polynomial list.
114     * @return true, if F is a partial Groebner base, else false.
115     */
116    public boolean isGBrec(int modv, List<GenPolynomial<GenPolynomial<C>>> F) {
117        if (F == null || F.isEmpty()) {
118            return true;
119        }
120        if (true) {
121            rbb = new GroebnerBasePseudoRecSeq<C>(F.get(0).ring.coFac);
122        }
123        return rbb.isGB(modv, F);
124    }
125
126
127    /**
128     * Partial permuation for specific variables. Computes a permutation perm
129     * for the variables vars, such that perm(vars) == pvars ... (vars \ pvars).
130     * Uses internal (reversed) variable sorting.
131     * @param vars names for all variables.
132     * @param pvars names for main variables, pvars subseteq vars.
133     * @return permutation for vars, such that perm(vars) == pvars ... (vars \
134     *         pvars).
135     */
136    public static List<Integer> partialPermutation(String[] vars, String[] pvars) {
137        return partialPermutation(vars, pvars, null);
138        //no: return getPermutation(vars,pvars);
139    }
140
141
142    /**
143     * Permutation of variables for elimination.
144     * @param aname variables for the full polynomial ring.
145     * @param ename variables for the elimination ring, subseteq aname.
146     * @return perm({vars \ ename},ename)
147     */
148    public static List<Integer> getPermutation(String[] aname, String[] ename) {
149        if (aname == null || ename == null) {
150            throw new IllegalArgumentException("aname or ename may not be null");
151        }
152        List<Integer> perm = new ArrayList<Integer>(aname.length);
153        // add ename permutation
154        for (int i = 0; i < ename.length; i++) {
155            int j = indexOf(ename[i], aname);
156            if (j < 0) {
157                throw new IllegalArgumentException("ename not contained in aname");
158            }
159            perm.add(j);
160        }
161        //System.out.println("perm_low = " + perm);
162        // add aname \ ename permutation
163        for (int i = 0; i < aname.length; i++) {
164            if (!perm.contains(i)) {
165                perm.add(i);
166            }
167        }
168        //System.out.println("perm_all = " + perm);
169        // reverse permutation indices
170        int n1 = aname.length - 1;
171        List<Integer> perm1 = new ArrayList<Integer>(aname.length);
172        for (Integer k : perm) {
173            perm1.add(n1 - k);
174        }
175        perm = perm1;
176        //System.out.println("perm_inv = " + perm1);
177        Collections.reverse(perm);
178        //System.out.println("perm_rev = " + perm);
179        return perm;
180    }
181
182
183    /**
184     * Index of s in A.
185     * @param s search string
186     * @param A string array
187     * @return i if s == A[i] for some i, else -1.
188     */
189    public static int indexOf(String s, String[] A) {
190        for (int i = 0; i < A.length; i++) {
191            if (s.equals(A[i])) {
192                return i;
193            }
194        }
195        return -1;
196    }
197
198
199    /**
200     * Partial permuation for specific variables. Computes a permutation perm
201     * for the variables vars, such that perm(vars) == pvars ... (vars \ pvars).
202     * Uses internal (reversed) variable sorting.
203     * @param vars names for all variables.
204     * @param pvars names for main variables, pvars subseteq vars.
205     * @param rvars names for remaining variables, rvars eq { vars \ pvars }.
206     * @return permutation for vars, such that perm(vars) == (pvars, {vars \
207     *         pvars}).
208     */
209    public static List<Integer> partialPermutation(String[] vars, String[] pvars, String[] rvars) {
210        if (vars == null || pvars == null) {
211            throw new IllegalArgumentException("no variable names found");
212        }
213        List<String> variables = new ArrayList<String>(vars.length);
214        List<String> pvariables = new ArrayList<String>(pvars.length);
215        for (int i = 0; i < vars.length; i++) {
216            variables.add(vars[i]);
217        }
218        for (int i = 0; i < pvars.length; i++) {
219            pvariables.add(pvars[i]);
220        }
221        if (rvars == null) {
222            rvars = remainingVars(vars, pvars);
223        }
224        List<String> rvariables = new ArrayList<String>(rvars.length);
225        for (int i = 0; i < rvars.length; i++) {
226            rvariables.add(rvars[i]);
227        }
228        if (rvars.length + pvars.length == vars.length) {
229            //System.out.println("pvariables  = " + pvariables);
230            return getPermutation(vars, rvars);
231        }
232        logger.info("not implemented for " + variables + " != " + pvariables + " cup " + rvariables);
233        throw new UnsupportedOperationException("not implemented");
234        /*
235        if (!variables.containsAll(pvariables) || !variables.containsAll(rvariables)) {
236            throw new IllegalArgumentException("partial variables not contained in all variables ");
237        }
238        Collections.reverse(variables);
239        Collections.reverse(pvariables);
240        Collections.reverse(rvariables);
241        System.out.println("variables  = " + variables);
242        System.out.println("pvariables = " + pvariables);
243        System.out.println("rvariables = " + rvariables);
244
245        List<Integer> perm = new ArrayList<Integer>();
246        List<Integer> pv = new ArrayList<Integer>();
247        for (String s : variables) {
248            int j = pvariables.indexOf(s);
249            if (j >= 0) {
250                perm.add(j);
251            }
252        }
253        int i = pvariables.size();
254        for (String s : variables) {
255            if (!pvariables.contains(s)) {
256                pv.add(i);
257            }
258            i++;
259        }
260
261        System.out.println("perm, 1 = " + perm);
262        //System.out.println("pv   = " + pv);
263        // sort perm according to pvars
264        int ps = perm.size(); // == pvars.length
265        for (int k = 0; k < ps; k++) {
266            for (int j = k + 1; j < ps; j++) {
267                int kk = variables.indexOf(pvariables.get(k));
268                int jj = variables.indexOf(pvariables.get(j));
269                if (kk > jj) { // swap
270                    int t = perm.get(k);
271                    System.out.println("swap " + t + " with " + perm.get(j));
272                    perm.set(k, perm.get(j));
273                    perm.set(j, t);
274                }
275            }
276        }
277        //System.out.println("perm = " + perm);
278        // sort pv according to rvars
279        int rs = pv.size(); // == rvars.length
280        for (int k = 0; k < rs; k++) {
281            for (int j = k + 1; j < rs; j++) {
282                int kk = variables.indexOf(rvariables.get(k));
283                int jj = variables.indexOf(rvariables.get(j));
284                if (kk > jj) { // swap
285                    int t = pv.get(k);
286                    //System.out.println("swap " + t + " with " + perm.get(j));
287                    pv.set(k, pv.get(j));
288                    pv.set(j, t);
289                }
290            }
291        }
292        //System.out.println("pv   = " + pv);
293        perm.addAll(pv);
294        System.out.println("perm, 2 = " + perm);
295        return perm;
296        */
297    }
298
299
300    /**
301     * Partial permuation for specific variables. Computes a permutation perm
302     * for the variables vars, such that perm(vars) == (evars, pvars, (vars \ {
303     * evars, pvars }). Uses internal (reversed) variable sorting.
304     * @param vars names for all variables.
305     * @param evars names for elimination variables, evars subseteq vars.
306     * @param pvars names for main variables, pvars subseteq vars.
307     * @param rvars names for remaining variables, rvars eq {vars \ { evars,
308     *            pvars } }.
309     * @return permutation for vars, such that perm(vars) == (evars,pvars, {vars
310     *         \ {evars,pvars}}.
311     */
312    public static List<Integer> partialPermutation(String[] vars, String[] evars, String[] pvars,
313                    String[] rvars) {
314        if (vars == null || evars == null || pvars == null) {
315            throw new IllegalArgumentException("not all variable names given");
316        }
317        String[] uvars;
318        if (rvars != null) {
319            uvars = new String[pvars.length + rvars.length];
320            for (int i = 0; i < pvars.length; i++) {
321                uvars[i] = pvars[i];
322            }
323            for (int i = 0; i < rvars.length; i++) {
324                uvars[pvars.length + i] = rvars[i];
325            }
326        } else {
327            uvars = pvars;
328        }
329        //System.out.println("uvars = " + Arrays.toString(uvars));
330        List<Integer> perm = partialPermutation(vars, evars, uvars);
331        return perm;
332    }
333
334
335    /**
336     * Remaining variables vars \ pvars. Uses internal (reversed) variable
337     * sorting, original order is preserved.
338     * @param vars names for all variables.
339     * @param pvars names for main variables, pvars subseteq vars.
340     * @return remaining vars = (vars \ pvars).
341     */
342    public static String[] remainingVars(String[] vars, String[] pvars) {
343        if (vars == null || pvars == null) {
344            throw new IllegalArgumentException("no variable names found");
345        }
346        List<String> variables = new ArrayList<String>(vars.length);
347        List<String> pvariables = new ArrayList<String>(pvars.length);
348        for (int i = 0; i < vars.length; i++) {
349            variables.add(vars[i]);
350        }
351        for (int i = 0; i < pvars.length; i++) {
352            pvariables.add(pvars[i]);
353        }
354        if (!variables.containsAll(pvariables)) {
355            throw new IllegalArgumentException("partial variables not contained in all variables ");
356        }
357        // variables.setMinus(pvariables)
358        List<String> rvariables = new ArrayList<String>(variables);
359        for (String s : pvariables) {
360            rvariables.remove(s);
361        }
362        int cl = vars.length - pvars.length;
363        String[] rvars = new String[cl];
364        int i = 0;
365        for (String s : rvariables) {
366            rvars[i++] = s;
367        }
368        return rvars;
369    }
370
371
372    /**
373     * Partial recursive Groebner base for specific variables. Computes Groebner
374     * base in K[vars \ pvars][pvars] with coefficients from K[vars \ pvars].
375     * @param F polynomial list.
376     * @param pvars names for main variables of partial Groebner base
377     *            computation.
378     * @return a container for a partial Groebner base of F wrt pvars.
379     */
380    public OptimizedPolynomialList<GenPolynomial<C>> partialGBrec(List<GenPolynomial<C>> F, String[] pvars) {
381        if (F == null || F.isEmpty()) {
382            throw new IllegalArgumentException("empty F not allowed");
383        }
384        GenPolynomialRing<C> fac = F.get(0).ring;
385        String[] vars = fac.getVars();
386        if (vars == null || pvars == null) {
387            throw new IllegalArgumentException("not all variable names found");
388        }
389        if (vars.length == pvars.length) {
390            throw new IllegalArgumentException("use non recursive partialGB algorithm");
391        }
392        // compute permutation (in reverse sorting)
393        List<Integer> perm = partialPermutation(vars, pvars);
394
395        GenPolynomialRing<C> pfac = fac.permutation(perm);
396        if (logger.isInfoEnabled()) {
397            logger.info("pfac = " + pfac);
398        }
399        List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, F);
400        //System.out.println("ppolys = " + ppolys);
401
402        int cl = fac.nvar - pvars.length; // > 0
403        int pl = pvars.length;
404        String[] rvars = remainingVars(vars, pvars);
405        GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(fac.coFac, cl, fac.tord, rvars);
406        //System.out.println("cfac = " + cfac);
407        GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pl,
408                        fac.tord, pvars);
409        if (logger.isInfoEnabled()) {
410            logger.info("rfac = " + rfac);
411        }
412        //System.out.println("rfac = " + rfac);
413
414        List<GenPolynomial<GenPolynomial<C>>> Fr = PolyUtil.<C> recursive(rfac, ppolys);
415        //System.out.println("\nFr = " + Fr);
416
417        if (true) {
418            rbb = new GroebnerBasePseudoRecSeq<C>(cfac);
419        }
420        List<GenPolynomial<GenPolynomial<C>>> Gr = rbb.GB(Fr);
421        //System.out.println("\nGr = " + Gr);
422        //perm = perm.subList(0,pl);
423        OptimizedPolynomialList<GenPolynomial<C>> pgb = new OptimizedPolynomialList<GenPolynomial<C>>(perm,
424                        rfac, Gr);
425        return pgb;
426    }
427
428
429    /**
430     * Partial Groebner base for specific variables. Computes Groebner base in
431     * K[vars \ pvars][pvars] with coefficients from K[vars \ pvars] but returns
432     * polynomials in K[vars \ pvars, pvars].
433     * @param F polynomial list.
434     * @param pvars names for main variables of partial Groebner base
435     *            computation.
436     * @return a container for a partial Groebner base of F wrt pvars.
437     */
438    public OptimizedPolynomialList<C> partialGB(List<GenPolynomial<C>> F, String[] pvars) {
439        if (F == null || F.isEmpty()) {
440            throw new IllegalArgumentException("empty F not allowed");
441        }
442        GenPolynomialRing<C> fac = F.get(0).ring;
443        String[] vars = fac.getVars();
444        // compute permutation (in reverse sorting)
445        //String[] xvars = remainingVars(vars, pvars);
446        //System.out.println("xvars = " + Arrays.toString(xvars));
447
448        List<Integer> perm = partialPermutation(vars, pvars);
449        //System.out.println("pGB, perm   = " + perm);
450        //System.out.println("pGB, perm,1 = " + getPermutation(vars, xvars));
451
452        GenPolynomialRing<C> pfac = fac.permutation(perm);
453        if (logger.isInfoEnabled()) {
454            logger.info("pfac = " + pfac);
455        }
456        List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, F);
457        //System.out.println("ppolys = " + ppolys);
458
459        int cl = fac.nvar - pvars.length;
460        if (cl == 0) { // non recursive case
461            //GroebnerBaseSeq<C> bb = new GroebnerBaseSeq<C>();
462            List<GenPolynomial<C>> G = bb.GB(ppolys);
463            OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G);
464            return pgb;
465        }
466        // recursive case
467        int pl = pvars.length;
468        String[] rvars = remainingVars(vars, pvars);
469        GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(fac.coFac, cl, fac.tord, rvars);
470        //System.out.println("cfac = " + cfac);
471
472        GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pl,
473                        fac.tord, pvars);
474        if (logger.isInfoEnabled()) {
475            logger.info("rfac = " + rfac);
476        }
477        //System.out.println("rfac = " + rfac);
478
479        List<GenPolynomial<GenPolynomial<C>>> Fr = PolyUtil.<C> recursive(rfac, ppolys);
480        //System.out.println("\nFr = " + Fr);
481
482        if (true) {
483            rbb = new GroebnerBasePseudoRecSeq<C>(cfac);
484        }
485        List<GenPolynomial<GenPolynomial<C>>> Gr = rbb.GB(Fr);
486        //System.out.println("\nGr = " + Gr);
487
488        List<GenPolynomial<C>> G = PolyUtil.<C> distribute(pfac, Gr);
489        //System.out.println("\nG = " + G);
490
491        OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G);
492        return pgb;
493    }
494
495
496    /**
497     * Partial Groebner base for specific variables. Computes Groebner base with
498     * coefficients from K[pvars] but returns polynomials in K[pvars, evars].
499     * @param F polynomial list.
500     * @param evars names for upper main variables of partial Groebner base
501     *            computation.
502     * @param pvars names for lower main variables of partial Groebner base
503     *            computation.
504     * @return a container for a partial Groebner base of F wrt (pvars,evars).
505     */
506    public OptimizedPolynomialList<C> elimPartialGB(List<GenPolynomial<C>> F, String[] evars, String[] pvars) {
507        if (F == null || F.isEmpty()) {
508            throw new IllegalArgumentException("empty F not allowed");
509        }
510        GenPolynomialRing<C> fac = F.get(0).ring;
511        String[] vars = fac.getVars();
512        // compute permutation (in reverse sorting)
513        //System.out.println("vars  = " + Arrays.toString(vars));
514        //System.out.println("evars = " + Arrays.toString(evars));
515        //System.out.println("pvars = " + Arrays.toString(pvars));
516        List<Integer> perm = partialPermutation(vars, evars, pvars);
517        //System.out.println("perm = " + perm);
518
519        GenPolynomialRing<C> pfac = fac.permutation(perm);
520        if (logger.isInfoEnabled()) {
521            logger.info("pfac = " + pfac);
522        }
523        List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, F);
524        //System.out.println("ppolys = " + ppolys);
525
526        int cl = fac.nvar - evars.length - pvars.length;
527        if (cl == 0) { // non recursive case
528            TermOrder to = pfac.tord;
529            int ev = to.getEvord();
530            //ev = TermOrder.IGRLEX;
531            TermOrder split = new TermOrder(ev, ev, pfac.nvar, evars.length);
532            pfac = new GenPolynomialRing<C>(pfac.coFac, pfac.nvar, split, pfac.getVars());
533            if (logger.isInfoEnabled()) {
534                //logger.info("split = " + split);
535                logger.info("pfac = " + pfac);
536            }
537            List<GenPolynomial<C>> Fs = new ArrayList<GenPolynomial<C>>(ppolys.size());
538            for (GenPolynomial<C> p : ppolys) {
539                Fs.add(pfac.copy(p));
540            }
541            List<GenPolynomial<C>> G = bb.GB(Fs);
542            OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G);
543            if (logger.isInfoEnabled()) {
544                logger.info("pgb = " + pgb);
545            }
546            return pgb;
547        }
548        logger.warn("not meaningful for elimination " + cl);
549        // recursive case
550        int pl = pvars.length + pvars.length;
551        String[] rvars = remainingVars(vars, evars);
552        rvars = remainingVars(rvars, pvars);
553        String[] uvars = new String[evars.length + pvars.length];
554        for (int i = 0; i < pvars.length; i++) {
555            uvars[i] = pvars[i];
556        }
557        for (int i = 0; i < evars.length; i++) {
558            uvars[pvars.length + i] = evars[i];
559        }
560
561        GenPolynomialRing<C> cfac = new GenPolynomialRing<C>(fac.coFac, cl, fac.tord, rvars);
562        //System.out.println("cfac = " + cfac);
563
564        TermOrder to = pfac.tord;
565        int ev = to.getEvord();
566        TermOrder split = new TermOrder(ev, ev, pl, evars.length);
567        //GenPolynomialRing<C> sfac = new GenPolynomialRing<C>(pfac.coFac, pfac.nvar, split, pfac.getVars());
568
569        GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, pl, split,
570                        uvars);
571        //System.out.println("rfac = " + rfac);
572
573        List<GenPolynomial<GenPolynomial<C>>> Fr = PolyUtil.<C> recursive(rfac, ppolys);
574        if (logger.isInfoEnabled()) {
575            logger.info("rfac = " + rfac);
576            logger.info("Fr   = " + Fr);
577        }
578
579        if (true) {
580            rbb = new GroebnerBasePseudoRecSeq<C>(cfac);
581        }
582        List<GenPolynomial<GenPolynomial<C>>> Gr = rbb.GB(Fr);
583        //System.out.println("\nGr = " + Gr);
584
585        List<GenPolynomial<C>> G = PolyUtil.<C> distribute(pfac, Gr);
586        //System.out.println("\nG = " + G);
587
588        OptimizedPolynomialList<C> pgb = new OptimizedPolynomialList<C>(perm, pfac, G);
589        return pgb;
590    }
591
592}