001    /*
002     * $Id: ReductionSeq.java 3345 2010-10-15 19:50:36Z kredel $
003     */
004    
005    package edu.jas.ps;
006    
007    
008    import java.util.ArrayList;
009    import java.util.List;
010    import java.util.Map;
011    
012    import org.apache.log4j.Logger;
013    
014    import edu.jas.poly.ExpVector;
015    import edu.jas.poly.GenPolynomial;
016    import edu.jas.poly.GenPolynomialRing;
017    import edu.jas.structure.RingElem;
018    
019    
020    /**
021     * Multivariate power series reduction sequential use algorithm. Implements Mora
022     * normal-form algorithm.
023     * @param <C> coefficient type
024     * @author Heinz Kredel
025     */
026    
027    public class ReductionSeq<C extends RingElem<C>> // should be FieldElem<C>>
028        /*todo: extends ReductionAbstract<C>*/{
029    
030    
031        private static final Logger logger = Logger.getLogger(ReductionSeq.class);
032    
033    
034        private final boolean debug = logger.isDebugEnabled();
035    
036    
037        /**
038         * Constructor.
039         */
040        public ReductionSeq() {
041        }
042    
043    
044        /**
045         * Module criterium.
046         * @param modv number of module variables.
047         * @param A power series.
048         * @param B power series.
049         * @return true if the module S-power-series(i,j) is required.
050         */
051        public boolean moduleCriterion(int modv, MultiVarPowerSeries<C> A, MultiVarPowerSeries<C> B) {
052            if (modv == 0) {
053                return true;
054            }
055            ExpVector ei = A.orderExpVector();
056            ExpVector ej = B.orderExpVector();
057            return moduleCriterion(modv, ei, ej);
058        }
059    
060    
061        /**
062         * Module criterion.
063         * @param modv number of module variables.
064         * @param ei ExpVector.
065         * @param ej ExpVector.
066         * @return true if the module S-power-series(i,j) is required.
067         */
068        public boolean moduleCriterion(int modv, ExpVector ei, ExpVector ej) {
069            if (modv == 0) {
070                return true;
071            }
072            if (ei.invLexCompareTo(ej, 0, modv) != 0) {
073                return false; // skip pair
074            }
075            return true;
076        }
077    
078    
079        /**
080         * GB criterion 4. Use only for commutative power series rings.
081         * @param A power series.
082         * @param B power series.
083         * @param e = lcm(ht(A),ht(B))
084         * @return true if the S-power-series(i,j) is required, else false.
085         */
086        public boolean criterion4(MultiVarPowerSeries<C> A, MultiVarPowerSeries<C> B, ExpVector e) {
087            if (logger.isInfoEnabled()) {
088                if (!A.ring.equals(B.ring)) {
089                    logger.error("rings not equal " + A.ring + ", " + B.ring);
090                }
091                if (!A.ring.isCommutative()) {
092                    logger.error("GBCriterion4 not applicabable to non-commutative power series");
093                    return true;
094                }
095            }
096            ExpVector ei = A.orderExpVector();
097            ExpVector ej = B.orderExpVector();
098            ExpVector g = ei.sum(ej);
099            // boolean t =  g == e ;
100            ExpVector h = g.subtract(e);
101            int s = h.signum();
102            return !(s == 0);
103        }
104    
105    
106        /**
107         * S-Power-series, S-polynomial.
108         * @param A power series.
109         * @param B power series.
110         * @return spol(A,B) the S-power-series of A and B.
111         */
112        public MultiVarPowerSeries<C> SPolynomial(MultiVarPowerSeries<C> A, MultiVarPowerSeries<C> B) {
113            if (B == null || B.isZERO()) {
114                if (A == null) {
115                    return B;
116                }
117                return A.ring.getZERO();
118            }
119            if (A == null || A.isZERO()) {
120                return B.ring.getZERO();
121            }
122            if (debug) {
123                if (!A.ring.equals(B.ring)) {
124                    logger.error("rings not equal " + A.ring + ", " + B.ring);
125                }
126            }
127            Map.Entry<ExpVector, C> ma = A.orderMonomial();
128            Map.Entry<ExpVector, C> mb = B.orderMonomial();
129    
130            ExpVector e = ma.getKey();
131            ExpVector f = mb.getKey();
132    
133            ExpVector g = e.lcm(f);
134            ExpVector e1 = g.subtract(e);
135            ExpVector f1 = g.subtract(f);
136    
137            C a = ma.getValue();
138            C b = mb.getValue();
139    
140            MultiVarPowerSeries<C> Ap = A.multiply(b, e1);
141            MultiVarPowerSeries<C> Bp = B.multiply(a, f1);
142            MultiVarPowerSeries<C> C = Ap.subtract(Bp);
143            return C;
144        }
145    
146    
147        /**
148         * Top normal-form with Mora's algorithm.
149         * @param Ap power series.
150         * @param Pp power series list.
151         * @return top-nf(Ap) with respect to Pp.
152         */
153        public MultiVarPowerSeries<C> normalform(List<MultiVarPowerSeries<C>> Pp, MultiVarPowerSeries<C> Ap) {
154            if (Pp == null || Pp.isEmpty()) {
155                return Ap;
156            }
157            if (Ap == null || Ap.isZERO()) {
158                return Ap;
159            }
160            if (!Ap.ring.coFac.isField()) {
161                throw new IllegalArgumentException("coefficients not from a field");
162            }
163            List<MultiVarPowerSeries<C>> P = new ArrayList<MultiVarPowerSeries<C>>(Pp.size());
164            synchronized (Pp) {
165                P.addAll(Pp);
166            }
167            ArrayList<ExpVector> htl = new ArrayList<ExpVector>(P.size());
168            ArrayList<C> lbc = new ArrayList<C>(P.size());
169            ArrayList<MultiVarPowerSeries<C>> p = new ArrayList<MultiVarPowerSeries<C>>(P.size());
170            ArrayList<Long> ecart = new ArrayList<Long>(P.size());
171            Map.Entry<ExpVector, C> m;
172            int j = 0;
173            for (int i = 0; i < P.size(); i++) {
174                m = P.get(i).orderMonomial();
175                //System.out.println("m_i = " + m);
176                if (m != null) {
177                    p.add(P.get(i));
178                    //System.out.println("e = " + m.getKey().toString(Ap.ring.vars));
179                    htl.add(m.getKey());
180                    lbc.add(m.getValue());
181                    ecart.add(P.get(i).ecart());
182                    j++;
183                }
184            }
185            int ll = j;
186            MultiVarPowerSeries<C> S = Ap;
187            //S.setTruncate(Ap.ring.truncate()); // ??
188            m = S.orderMonomial();
189            while (true) {
190                //System.out.println("m = " + m);
191                //System.out.println("S = " + S);
192                if (m == null) {
193                    return S;
194                }
195                if (S.isZERO()) {
196                    return S;
197                }
198                ExpVector e = m.getKey();
199                if (debug) {
200                    logger.debug("e = " + e.toString(Ap.ring.vars));
201                }
202                // search ps with ht(ps) | ht(S)
203                List<Integer> li = new ArrayList<Integer>();
204                int i;
205                for (i = 0; i < htl.size(); i++) {
206                    if (e.multipleOf(htl.get(i))) {
207                        //System.out.println("m = " + m);
208                        li.add(i);
209                    }
210                }
211                if (li.isEmpty()) {
212                    return S;
213                }
214                //System.out.println("li = " + li);
215                // select ps with smallest ecart
216                long mi = Long.MAX_VALUE;
217                //String es = "";
218                for (int k = 0; k < li.size(); k++) {
219                    int ki = li.get(k);
220                    long x = ecart.get(ki); //p.get( ki ).ecart();
221                    //es = es + x + " ";
222                    if (x < mi) { // first < or last <= ?
223                        mi = x;
224                        i = ki;
225                    }
226                }
227                //System.out.println("li = " + li + ", ecarts = " + es);
228                //System.out.println("i = " + i + ", p_i = " + p.get(i));
229                //if ( i <= ll ) {
230                //} else {
231                //    System.out.println("i = " + i + ", ll = " + ll);
232                //}
233                long si = S.ecart();
234                if (mi > si) {
235                    //System.out.println("ecart_i = " + mi + ", ecart_S = " + si + ", S+ = " + S);
236                    p.add(S);
237                    htl.add(m.getKey());
238                    lbc.add(m.getValue());
239                    ecart.add(si);
240                }
241                e = e.subtract(htl.get(i));
242                C a = m.getValue().divide(lbc.get(i));
243                MultiVarPowerSeries<C> Q = p.get(i).multiply(a, e);
244                S = S.subtract(Q);
245                m = S.orderMonomial();
246            }
247        }
248    
249    
250        /**
251         * Total reduced normal-form with Mora's algorithm.
252         * @param A power series.
253         * @param P power series list.
254         * @return total-nf(A) with respect to P.
255         */
256        public MultiVarPowerSeries<C> totalNormalform(List<MultiVarPowerSeries<C>> P, MultiVarPowerSeries<C> A) {
257            if (P == null || P.isEmpty()) {
258                return A;
259            }
260            if (A == null) {
261                return A;
262            }
263            MultiVarPowerSeries<C> R = normalform(P, A);
264            if (R.isZERO()) {
265                return R;
266            }
267            MultiVarCoefficients<C> Rc = new MultiVarCoefficients<C>(A.ring) {
268    
269    
270                @Override
271                public C generate(ExpVector i) { // will not be used
272                    return pfac.coFac.getZERO();
273                }
274            };
275            GenPolynomialRing<C> pfac = A.lazyCoeffs.pfac;
276            while (!R.isZERO()) {
277                Map.Entry<ExpVector, C> m = R.orderMonomial();
278                if ( m == null ) {
279                    break;
280                }
281                R = R.reductum();
282                ExpVector e = m.getKey();
283                long t = e.totalDeg();
284                GenPolynomial<C> p = Rc.coeffCache.get(t);
285                if (p == null) {
286                    p = pfac.getZERO();
287                }
288                p = p.sum(m.getValue(), e);
289                Rc.coeffCache.put(t, p);
290                // zeros need never update
291    
292                R = normalform(P, R);
293            }
294            R = R.sum(Rc);
295            //System.out.println("R+Rc = " + R);
296            return R;
297        }
298    
299    
300        /**
301         * Total reduced normalform with Mora's algorithm.
302         * @param P power series list.
303         * @return total-nf(p) for p with respect to P\{p}.
304         */
305        public List<MultiVarPowerSeries<C>> totalNormalform(List<MultiVarPowerSeries<C>> P) {
306            if (P == null || P.isEmpty()) {
307                return P;
308            }
309            //StandardBaseSeq<C> std = new StandardBaseSeq<C>();
310            List<MultiVarPowerSeries<C>> R = new ArrayList<MultiVarPowerSeries<C>>(P.size());
311            List<MultiVarPowerSeries<C>> S = new ArrayList<MultiVarPowerSeries<C>>(P);
312            for (MultiVarPowerSeries<C> a : P) {
313                //S.remove(a);
314                //if ( !std.isSTD(S) ) {
315                //    System.out.println("a = " + a);
316                //}
317                Map.Entry<ExpVector, C> m = a.orderMonomial();
318                if ( m == null ) {
319                    //S.add(a);
320                    continue;
321                }
322                MultiVarPowerSeries<C> r = a.reductum();
323    
324                MultiVarPowerSeries<C> b = normalform(S, r);
325                // need also unit of reduction: u r --> b
326                // b = b.multiply(u);
327                b = b.sum(m);
328                if ( !b.isZERO() ) {
329                    R.add(b);
330                }
331            }
332            return R;
333        }
334    
335    
336        /**
337         * Is top reducible.
338         * @param A power series.
339         * @param P power series list.
340         * @return true if A is top reducible with respect to P.
341         */
342        public boolean isTopReducible(List<MultiVarPowerSeries<C>> P, MultiVarPowerSeries<C> A) {
343            if (P == null || P.isEmpty()) {
344                return false;
345            }
346            if (A == null) {
347                return false;
348            }
349            ExpVector e = A.orderExpVector();
350            if (e == null) {
351                return false;
352            }
353            for (MultiVarPowerSeries<C> p : P) {
354                ExpVector ep = p.orderExpVector();
355                if (e == null) {
356                    continue;
357                }
358                if (e.multipleOf(ep)) {
359                    return true;
360                }
361            }
362            return false;
363        }
364    
365    
366        /**
367         * Ideal containment. Test if each b in B is contained in ideal S.
368         * @param S standard base.
369         * @param B list of power series
370         * @return true, if each b in B is contained in ideal(S), else false
371         */
372        public boolean contains(List<MultiVarPowerSeries<C>> S, List<MultiVarPowerSeries<C>> B) {
373            if (B == null || B.size() == 0) {
374                return true;
375            }
376            if (S == null || S.size() == 0) {
377                return true;
378            }
379            for (MultiVarPowerSeries<C> b : B) {
380                if (b == null) {
381                    continue;
382                }
383                MultiVarPowerSeries<C> z = normalform(S, b);
384                if (!z.isZERO()) {
385                    System.out.println("contains nf(b) != 0: " + b + ", z = " + z);
386                    return false;
387                }
388            }
389            return true;
390        }
391    
392    }