001/*
002 * $Id: TermOrderOptimization.java 5818 2018-05-10 16:40:12Z kredel $
003 */
004
005package edu.jas.poly;
006
007
008import java.util.Arrays;
009import java.util.ArrayList;
010import java.util.Collection;
011import java.util.List;
012import java.util.Map;
013import java.util.SortedMap;
014import java.util.TreeMap;
015
016import org.apache.log4j.Logger;
017
018import edu.jas.arith.BigInteger;
019import edu.jas.structure.RingElem;
020import edu.jas.vector.GenVector;
021import edu.jas.vector.GenVectorModul;
022
023
024/**
025 * Term order optimization. See mas10/maspoly/DIPTOO.m{di}.
026 * @author Heinz Kredel
027 */
028
029public class TermOrderOptimization {
030
031
032    private static final Logger logger = Logger.getLogger(TermOrderOptimization.class);
033
034
035    //private static final boolean debug = logger.isDebugEnabled();
036
037
038    /**
039     * Degree matrix.
040     * @param A polynomial to be considered.
041     * @return degree matrix.
042     */
043    public static <C extends RingElem<C>> List<GenPolynomial<BigInteger>> degreeMatrix(GenPolynomial<C> A) {
044
045        List<GenPolynomial<BigInteger>> dem = null;
046        if (A == null) {
047            return dem;
048        }
049
050        BigInteger cfac = new BigInteger();
051        GenPolynomialRing<BigInteger> ufac = new GenPolynomialRing<BigInteger>(cfac, 1);
052
053        int nvar = A.numberOfVariables();
054        dem = new ArrayList<GenPolynomial<BigInteger>>(nvar);
055
056        for (int i = 0; i < nvar; i++) {
057            dem.add(ufac.getZERO());
058        }
059        if (A.isZERO()) {
060            return dem;
061        }
062
063        for (ExpVector e : A.getMap().keySet()) {
064            dem = expVectorAdd(dem, e);
065        }
066        return dem;
067    }
068
069
070    /**
071     * Degree matrix exponent vector add.
072     * @param dm degree matrix.
073     * @param e exponent vector.
074     * @return degree matrix + e.
075     */
076    public static List<GenPolynomial<BigInteger>> expVectorAdd(List<GenPolynomial<BigInteger>> dm, ExpVector e) {
077        for (int i = 0; i < dm.size() && i < e.length(); i++) {
078            GenPolynomial<BigInteger> p = dm.get(i);
079            long u = e.getVal(i);
080            ExpVector f = ExpVector.create(1, 0, u);
081            p = p.sum(p.ring.getONECoefficient(), f);
082            dm.set(i, p);
083        }
084        return dm;
085    }
086
087
088    /**
089     * Degree matrix of coefficient polynomials.
090     * @param A polynomial to be considered.
091     * @return degree matrix for the coeficients.
092     */
093    public static <C extends RingElem<C>> List<GenPolynomial<BigInteger>> degreeMatrixOfCoefficients(
094                    GenPolynomial<GenPolynomial<C>> A) {
095        if (A == null) {
096            throw new IllegalArgumentException("polynomial must not be null");
097        }
098        return degreeMatrix(A.getMap().values());
099    }
100
101
102    /**
103     * Degree matrix.
104     * @param L list of polynomial to be considered.
105     * @return degree matrix.
106     */
107    public static <C extends RingElem<C>> List<GenPolynomial<BigInteger>> degreeMatrix(
108                    Collection<GenPolynomial<C>> L) {
109        if (L == null) {
110            throw new IllegalArgumentException("list must be non null");
111        }
112        GenVectorModul<GenPolynomial<BigInteger>> vmblas = null;
113        GenVector<GenPolynomial<BigInteger>> vdem = null;
114        for (GenPolynomial<C> p : L) {
115            List<GenPolynomial<BigInteger>> dm = degreeMatrix(p);
116            if (vdem == null) {
117                vmblas = new GenVectorModul<GenPolynomial<BigInteger>>(dm.get(0).ring, dm.size());
118                vdem = new GenVector<GenPolynomial<BigInteger>>(vmblas, dm);
119            } else {
120                vdem = vdem.sum(new GenVector<GenPolynomial<BigInteger>>(vmblas, dm));
121            }
122        }
123        return vdem.val;
124    }
125
126
127    /**
128     * Degree matrix of coefficient polynomials.
129     * @param L list of polynomial to be considered.
130     * @return degree matrix for the coeficients.
131     */
132    public static <C extends RingElem<C>> List<GenPolynomial<BigInteger>> degreeMatrixOfCoefficients(
133                    Collection<GenPolynomial<GenPolynomial<C>>> L) {
134        if (L == null) {
135            throw new IllegalArgumentException("list must not be null");
136        }
137        GenVectorModul<GenPolynomial<BigInteger>> vmblas = null;
138        GenVector<GenPolynomial<BigInteger>> vdem = null;
139        for (GenPolynomial<GenPolynomial<C>> p : L) {
140            List<GenPolynomial<BigInteger>> dm = degreeMatrixOfCoefficients(p);
141            if (vdem == null) {
142                vmblas = new GenVectorModul<GenPolynomial<BigInteger>>(dm.get(0).ring, dm.size());
143                vdem = new GenVector<GenPolynomial<BigInteger>>(vmblas, dm);
144            } else {
145                vdem = vdem.sum(new GenVector<GenPolynomial<BigInteger>>(vmblas, dm));
146            }
147        }
148        return vdem.val;
149    }
150
151
152    /**
153     * Optimal permutation for the Degree matrix.
154     * @param D degree matrix.
155     * @return optimal permutation for D.
156     */
157    public static List<Integer> optimalPermutation(List<GenPolynomial<BigInteger>> D) {
158        if (D == null) {
159            throw new IllegalArgumentException("list must be non null");
160        }
161        List<Integer> P = new ArrayList<Integer>(D.size());
162        if (D.size() == 0) {
163            return P;
164        }
165        if (D.size() == 1) {
166            P.add(0);
167            return P;
168        }
169        SortedMap<GenPolynomial<BigInteger>, List<Integer>> map = new TreeMap<GenPolynomial<BigInteger>, List<Integer>>();
170        int i = 0;
171        for (GenPolynomial<BigInteger> p : D) {
172            List<Integer> il = map.get(p);
173            if (il == null) {
174                il = new ArrayList<Integer>(3);
175            }
176            il.add(i);
177            map.put(p, il);
178            i++;
179        }
180        List<List<Integer>> V = new ArrayList<List<Integer>>(map.values());
181        //System.out.println("V = " + V);
182        if (logger.isDebugEnabled()) {
183            logger.info("V = " + V);
184        }
185        //for ( int j = V.size()-1; j >= 0; j-- ) {
186        for (int j = 0; j < V.size(); j++) {
187            List<Integer> v = V.get(j);
188            for (Integer k : v) {
189                P.add(k);
190            }
191        }
192        return P;
193    }
194
195
196    /**
197     * Inverse of a permutation.
198     * @param P permutation.
199     * @return S with S*P = id.
200     */
201    public static List<Integer> inversePermutation(List<Integer> P) {
202        if (P == null || P.size() <= 1) {
203            return P;
204        }
205        List<Integer> ip = new ArrayList<Integer>(P); // ensure size and content
206        for (int i = 0; i < P.size(); i++) {
207            ip.set(P.get(i), i); // inverse
208        }
209        return ip;
210    }
211
212
213    /**
214     * Test for identity permutation.
215     * @param P permutation.
216     * @return true , if P = id, else false.
217     */
218    public static boolean isIdentityPermutation(List<Integer> P) {
219        if (P == null || P.size() <= 1) {
220            return true;
221        }
222        for (int i = 0; i < P.size(); i++) {
223            if (P.get(i).intValue() != i) {
224                return false;
225            }
226        }
227        return true;
228    }
229
230
231    /**
232     * Multiplication permutations.
233     * @param P permutation.
234     * @param S permutation.
235     * @return P*S.
236     */
237    public static List<Integer> multiplyPermutation(List<Integer> P, List<Integer> S) {
238        if (P == null || S == null) {
239            return null;
240        }
241        if (P.size() != S.size()) {
242            throw new IllegalArgumentException("#P != #S: P =" + P + ", S = " + S);
243        }
244        List<Integer> ip = new ArrayList<Integer>(P); // ensure size and content
245        for (int i = 0; i < P.size(); i++) {
246            ip.set(i, S.get(P.get(i)));
247        }
248        return ip;
249    }
250
251
252    /**
253     * Permutation of a list.
254     * @param L list.
255     * @param P permutation.
256     * @return P(L).
257     */
258    @SuppressWarnings("cast")
259    public static <T> List<T> listPermutation(List<Integer> P, List<T> L) {
260        if (L == null || L.size() <= 1) {
261            return L;
262        }
263        List<T> pl = new ArrayList<T>(L.size());
264        for (Integer i : P) {
265            pl.add(L.get((int) i));
266        }
267        return pl;
268    }
269
270
271    /**
272     * Permutation of an array. Compiles, but does not work, requires JDK 1.6 to
273     * work.
274     * @param a array.
275     * @param P permutation.
276     * @return P(a).
277     */
278    @SuppressWarnings({ "unchecked", "cast" })
279    public static <T> T[] arrayPermutation(List<Integer> P, T[] a) {
280        if (a == null || a.length <= 1) {
281            return a;
282        }
283        //T[] b = (T[]) new Object[a.length]; // jdk 1.5 
284        T[] b = Arrays.<T> copyOf( a, a.length ); // jdk 1.6, works
285        int j = 0;
286        for (Integer i : P) {
287            b[j] = a[(int) i];
288            j++;
289        }
290        return b;
291    }
292
293
294    /**
295     * Permutation of polynomial exponent vectors.
296     * @param A polynomial.
297     * @param R polynomial ring.
298     * @param P permutation.
299     * @return P(A).
300     */
301    public static <C extends RingElem<C>> GenPolynomial<C> permutation(List<Integer> P,
302                    GenPolynomialRing<C> R, GenPolynomial<C> A) {
303        if (A == null) {
304            return A;
305        }
306        GenPolynomial<C> B = R.getZERO().copy();
307        Map<ExpVector, C> Bv = B.val; //getMap();
308        for (Map.Entry<ExpVector, C> y : A.getMap().entrySet()) {
309            ExpVector e = y.getKey();
310            C a = y.getValue();
311            //System.out.println("e = " + e);
312            ExpVector f = e.permutation(P);
313            //System.out.println("f = " + f);
314            Bv.put(f, a); // assert f not in Bv
315        }
316        return B;
317    }
318
319
320    /**
321     * Permutation of polynomial exponent vectors.
322     * @param L list of polynomials.
323     * @param R polynomial ring.
324     * @param P permutation.
325     * @return P(L).
326     */
327    public static <C extends RingElem<C>> List<GenPolynomial<C>> permutation(List<Integer> P,
328                    GenPolynomialRing<C> R, List<GenPolynomial<C>> L) {
329        if (L == null || L.size() == 0) {
330            return L;
331        }
332        List<GenPolynomial<C>> K = new ArrayList<GenPolynomial<C>>(L.size());
333        for (GenPolynomial<C> a : L) {
334            GenPolynomial<C> b = permutation(P, R, a);
335            K.add(b);
336        }
337        return K;
338    }
339
340
341    /**
342     * Permutation of solvable polynomial exponent vectors.
343     * @param L list of solvable polynomials.
344     * @param R solvable polynomial ring.
345     * @param P permutation, must be compatible with the commutator relations.
346     * @return P(L).
347     */
348    public static <C extends RingElem<C>> List<GenSolvablePolynomial<C>> permutation(List<Integer> P,
349                    GenSolvablePolynomialRing<C> R, List<GenSolvablePolynomial<C>> L) {
350        if (L == null || L.size() == 0) {
351            return L;
352        }
353        List<GenSolvablePolynomial<C>> K = new ArrayList<GenSolvablePolynomial<C>>(L.size());
354        for (GenSolvablePolynomial<C> a : L) {
355            GenSolvablePolynomial<C> b;
356            b = (GenSolvablePolynomial<C>) permutation(P, (GenPolynomialRing<C>) R, (GenPolynomial<C>) a);
357            K.add(b);
358        }
359        return K;
360    }
361
362
363    /**
364     * Permutation of polynomial exponent vectors of coefficient polynomials.
365     * @param A polynomial.
366     * @param R polynomial ring.
367     * @param P permutation.
368     * @return P(A).
369     */
370    public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<C>> permutationOnCoefficients(
371                    List<Integer> P, GenPolynomialRing<GenPolynomial<C>> R, GenPolynomial<GenPolynomial<C>> A) {
372        if (A == null) {
373            return A;
374        }
375        GenPolynomial<GenPolynomial<C>> B = R.getZERO().copy();
376        GenPolynomialRing<C> cf = (GenPolynomialRing<C>) R.coFac;
377        Map<ExpVector, GenPolynomial<C>> Bv = B.val; //getMap();
378        for (Map.Entry<ExpVector, GenPolynomial<C>> y : A.getMap().entrySet()) {
379            ExpVector e = y.getKey();
380            GenPolynomial<C> a = y.getValue();
381            //System.out.println("e = " + e);
382            GenPolynomial<C> b = permutation(P, cf, a);
383            //System.out.println("b = " + b);
384            Bv.put(e, b); // assert e not in Bv
385        }
386        return B;
387    }
388
389
390    /**
391     * Permutation of polynomial exponent vectors of coefficients.
392     * @param L list of polynomials.
393     * @param R polynomial ring.
394     * @param P permutation.
395     * @return P(L).
396     */
397    public static <C extends RingElem<C>> List<GenPolynomial<GenPolynomial<C>>> permutationOnCoefficients(
398                    List<Integer> P, GenPolynomialRing<GenPolynomial<C>> R,
399                    List<GenPolynomial<GenPolynomial<C>>> L) {
400        if (L == null || L.size() == 0) {
401            return L;
402        }
403        List<GenPolynomial<GenPolynomial<C>>> K = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L.size());
404        for (GenPolynomial<GenPolynomial<C>> a : L) {
405            GenPolynomial<GenPolynomial<C>> b = permutationOnCoefficients(P, R, a);
406            K.add(b);
407        }
408        return K;
409    }
410
411
412    /**
413     * Permutation of polynomial ring variables.
414     * @param R polynomial ring.
415     * @param P permutation.
416     * @return P(R).
417     */
418    public static <C extends RingElem<C>> GenPolynomialRing<C> permutation(List<Integer> P,
419                    GenPolynomialRing<C> R) {
420        return R.permutation(P);
421    }
422
423
424    /**
425     * Optimize variable order.
426     * @param R polynomial ring.
427     * @param L list of polynomials.
428     * @return optimized polynomial list.
429     */
430    public static <C extends RingElem<C>> OptimizedPolynomialList<C> optimizeTermOrder(
431                    GenPolynomialRing<C> R, List<GenPolynomial<C>> L) {
432        List<GenPolynomial<C>> Lp = new ArrayList<GenPolynomial<C>>(L);
433        if (R instanceof GenSolvablePolynomialRing) { // look also on solvable relations
434            GenSolvablePolynomialRing<C> Rs = (GenSolvablePolynomialRing<C>) R;
435            Lp.addAll(Rs.table.relationList());
436        }
437        List<Integer> perm = optimalPermutation(degreeMatrix(Lp));
438        GenPolynomialRing<C> pring = R.permutation(perm);
439        List<GenPolynomial<C>> ppolys = permutation(perm, pring, L);
440        OptimizedPolynomialList<C> op = new OptimizedPolynomialList<C>(perm, pring, ppolys);
441        return op;
442    }
443
444
445    /**
446     * Optimize variable order.
447     * @param P polynomial list.
448     * @return optimized polynomial list.
449     */
450    public static <C extends RingElem<C>> OptimizedPolynomialList<C> optimizeTermOrder(PolynomialList<C> P) {
451        if (P == null) {
452            return null;
453        }
454        return optimizeTermOrder(P.ring, P.list);
455    }
456
457
458    /**
459     * Optimize variable order on coefficients.
460     * @param P polynomial list.
461     * @return optimized polynomial list.
462     */
463    public static <C extends RingElem<C>> OptimizedPolynomialList<GenPolynomial<C>> optimizeTermOrderOnCoefficients(
464                    PolynomialList<GenPolynomial<C>> P) {
465        return optimizeTermOrderOnCoefficients(P.ring, P.list);
466    }
467
468
469    /**
470     * Optimize variable order on coefficients.
471     * @param ring polynomial ring.
472     * @param L list of polynomials.
473     * @return optimized polynomial list.
474     */
475    @SuppressWarnings("cast")
476    public static <C extends RingElem<C>> OptimizedPolynomialList<GenPolynomial<C>> optimizeTermOrderOnCoefficients(
477                    GenPolynomialRing<GenPolynomial<C>> ring, List<GenPolynomial<GenPolynomial<C>>> L) {
478        if (L == null) {
479            return null;
480        }
481        List<GenPolynomial<GenPolynomial<C>>> Lp = new ArrayList<GenPolynomial<GenPolynomial<C>>>(L);
482        //GenPolynomialRing<GenPolynomial<C>> ring = P.ring;
483        if (ring instanceof GenSolvablePolynomialRing) { // look also on solvable relations
484            GenSolvablePolynomialRing<GenPolynomial<C>> Rs = (GenSolvablePolynomialRing<GenPolynomial<C>>) ring;
485            Lp.addAll(Rs.table.relationList());
486        }
487        List<Integer> perm = optimalPermutation(degreeMatrixOfCoefficients(Lp));
488
489        GenPolynomialRing<C> coFac = (GenPolynomialRing<C>) ring.coFac;
490        GenPolynomialRing<C> pFac = coFac.permutation(perm);
491        GenSolvablePolynomialRing<GenPolynomial<C>> sring, psring;
492        GenPolynomialRing<GenPolynomial<C>> pring;
493        if (ring instanceof GenSolvablePolynomialRing) { // permute also solvable relations
494            sring = (GenSolvablePolynomialRing<GenPolynomial<C>>) ring;
495            psring = new GenSolvablePolynomialRing<GenPolynomial<C>>(pFac, sring);
496            List<GenPolynomial<GenPolynomial<C>>> ir = PolynomialList
497                            .<GenPolynomial<C>> castToList(sring.table.relationList());
498            ir = permutationOnCoefficients(perm, psring, ir);
499            psring.addRelations(ir);
500            pring = (GenPolynomialRing<GenPolynomial<C>>) psring;
501        } else {
502            pring = new GenPolynomialRing<GenPolynomial<C>>(pFac, ring);
503        }
504        List<GenPolynomial<GenPolynomial<C>>> ppolys;
505        ppolys = permutationOnCoefficients(perm, pring, L);
506
507        OptimizedPolynomialList<GenPolynomial<C>> op;
508        op = new OptimizedPolynomialList<GenPolynomial<C>>(perm, pring, ppolys);
509        return op;
510    }
511
512
513    /**
514     * Optimize variable order.
515     * @param P module list.
516     * @return optimized module list.
517     */
518    public static <C extends RingElem<C>> OptimizedModuleList<C> optimizeTermOrder(ModuleList<C> P) {
519        if (P == null) {
520            return null;
521        }
522        return optimizeTermOrderModule(P.ring, P.list);
523    }
524
525
526    /**
527     * Optimize variable order.
528     * @param R polynomial ring.
529     * @param L list of lists of polynomials.
530     * @return optimized module list.
531     */
532    public static <C extends RingElem<C>> OptimizedModuleList<C> optimizeTermOrderModule(
533                    GenPolynomialRing<C> R, List<List<GenPolynomial<C>>> L) {
534        List<GenPolynomial<C>> M = new ArrayList<GenPolynomial<C>>();
535        for (List<GenPolynomial<C>> ll : L) {
536            M.addAll(ll);
537        }
538        if (R instanceof GenSolvablePolynomialRing) { // look also on solvable relations
539            GenSolvablePolynomialRing<C> Rs = (GenSolvablePolynomialRing<C>) R;
540            M.addAll(Rs.table.relationList());
541        }
542        List<Integer> perm = optimalPermutation(degreeMatrix(M));
543        GenPolynomialRing<C> pring = R.permutation(perm);
544        List<List<GenPolynomial<C>>> mpolys = new ArrayList<List<GenPolynomial<C>>>();
545        List<GenPolynomial<C>> pp;
546        for (List<GenPolynomial<C>> ll : L) {
547            pp = permutation(perm, pring, ll);
548            mpolys.add(pp);
549        }
550        OptimizedModuleList<C> op = new OptimizedModuleList<C>(perm, pring, mpolys);
551        return op;
552    }
553
554
555    /**
556     * Optimize variable order on coefficients.
557     * @param P module list.
558     * @return optimized module list.
559     */
560    @SuppressWarnings("cast")
561    public static <C extends RingElem<C>> OptimizedModuleList<GenPolynomial<C>> optimizeTermOrderOnCoefficients(
562                    ModuleList<GenPolynomial<C>> P) {
563        if (P == null) {
564            return null;
565        }
566        GenPolynomialRing<GenPolynomial<C>> ring = P.ring;
567        List<GenPolynomial<GenPolynomial<C>>> M = new ArrayList<GenPolynomial<GenPolynomial<C>>>();
568        for (List<GenPolynomial<GenPolynomial<C>>> ll : P.list) {
569            M.addAll(ll);
570        }
571        if (ring instanceof GenSolvablePolynomialRing) { // look also on solvable relations
572            GenSolvablePolynomialRing<GenPolynomial<C>> Rs = (GenSolvablePolynomialRing<GenPolynomial<C>>) ring;
573            M.addAll(Rs.table.relationList());
574        }
575        List<Integer> perm = optimalPermutation(degreeMatrixOfCoefficients(M));
576
577        GenPolynomialRing<C> coFac = (GenPolynomialRing<C>) ring.coFac;
578        GenPolynomialRing<C> pFac = coFac.permutation(perm);
579        GenSolvablePolynomialRing<GenPolynomial<C>> sring, psring;
580        GenPolynomialRing<GenPolynomial<C>> pring;
581        if (ring instanceof GenSolvablePolynomialRing) { // permute also solvable relations
582            sring = (GenSolvablePolynomialRing<GenPolynomial<C>>) ring;
583            psring = new GenSolvablePolynomialRing<GenPolynomial<C>>(pFac, sring);
584            List<GenPolynomial<GenPolynomial<C>>> ir = PolynomialList
585                            .<GenPolynomial<C>> castToList(sring.table.relationList());
586            ir = permutationOnCoefficients(perm, psring, ir);
587            psring.addRelations(ir);
588            pring = (GenPolynomialRing<GenPolynomial<C>>) psring;
589        } else {
590            pring = new GenPolynomialRing<GenPolynomial<C>>(pFac, ring);
591        }
592        List<GenPolynomial<GenPolynomial<C>>> pp;
593        List<List<GenPolynomial<GenPolynomial<C>>>> mpolys;
594        mpolys = new ArrayList<List<GenPolynomial<GenPolynomial<C>>>>();
595        for (List<GenPolynomial<GenPolynomial<C>>> ll : P.list) {
596            pp = permutationOnCoefficients(perm, pring, ll);
597            mpolys.add(pp);
598        }
599        OptimizedModuleList<GenPolynomial<C>> op = new OptimizedModuleList<GenPolynomial<C>>(perm, pring,
600                        mpolys);
601        return op;
602    }
603
604}