001/*
002 * $Id: PseudoReductionSeq.java 5841 2018-05-20 21:26:13Z kredel $
003 */
004
005package edu.jas.gbufd;
006
007
008import java.util.List;
009import java.util.Map;
010
011import org.apache.log4j.Logger;
012
013import edu.jas.gb.ReductionAbstract;
014import edu.jas.poly.ExpVector;
015import edu.jas.poly.GenPolynomial;
016import edu.jas.poly.PolyUtil;
017import edu.jas.structure.RingElem;
018
019
020/**
021 * Polynomial pseudo reduction sequential use algorithm. Coefficients of
022 * polynomials must not be from a field, i.e. the fraction free reduction is
023 * implemented. Implements normalform.
024 * @param <C> coefficient type
025 * @author Heinz Kredel
026 */
027
028public class PseudoReductionSeq<C extends RingElem<C>> extends ReductionAbstract<C> implements
029                PseudoReduction<C> {
030
031
032    private static final Logger logger = Logger.getLogger(PseudoReductionSeq.class);
033
034
035    private static final boolean debug = logger.isDebugEnabled();
036
037
038    /**
039     * Constructor.
040     */
041    public PseudoReductionSeq() {
042    }
043
044
045    /**
046     * Normalform.
047     * @param Ap polynomial.
048     * @param Pp polynomial list.
049     * @return nf(Ap) with respect to Pp.
050     */
051    @SuppressWarnings("unchecked")
052    public GenPolynomial<C> normalform(List<GenPolynomial<C>> Pp, GenPolynomial<C> Ap) {
053        if (Pp == null || Pp.isEmpty()) {
054            return Ap;
055        }
056        if (Ap == null || Ap.isZERO()) {
057            return Ap;
058        }
059        Map.Entry<ExpVector, C> m;
060        GenPolynomial<C>[] P = new GenPolynomial[0];
061        synchronized (Pp) {
062            P = Pp.toArray(P);
063        }
064        int l = P.length;
065        ExpVector[] htl = new ExpVector[l];
066        C[] lbc = (C[]) new RingElem[l];
067        GenPolynomial<C>[] p = new GenPolynomial[l];
068        int i;
069        int j = 0;
070        for (i = 0; i < l; i++) {
071            if (P[i] == null) {
072                continue;
073            }
074            p[i] = P[i];
075            m = p[i].leadingMonomial();
076            if (m != null) {
077                p[j] = p[i];
078                htl[j] = m.getKey();
079                lbc[j] = m.getValue();
080                j++;
081            }
082        }
083        l = j;
084        ExpVector e, f;
085        C a, b;
086        boolean mt = false;
087        GenPolynomial<C> R = Ap.ring.getZERO().copy();
088
089        GenPolynomial<C> S = Ap.copy();
090        while (S.length() > 0) {
091            m = S.leadingMonomial();
092            e = m.getKey();
093            a = m.getValue();
094            for (i = 0; i < l; i++) {
095                mt = e.multipleOf(htl[i]);
096                if (mt)
097                    break;
098            }
099            if (!mt) {
100                //logger.debug("irred");
101                //R = R.sum(a, e);
102                //S = S.subtract(a, e);
103                R.doPutToMap(e, a);
104                S.doRemoveFromMap(e, a);
105                //System.out.println(" S = " + S);
106            } else {
107                f = e.subtract(htl[i]);
108                //logger.info("red div = " + e);
109                @SuppressWarnings("unchecked")
110                C c = (C) lbc[i];
111                if (a.remainder(c).isZERO()) { //c.isUnit() ) {
112                    b = a.divide(c);
113                    GenPolynomial<C> Sp = S.subtractMultiple(b, f, p[i]);
114                    if (e.equals(Sp.leadingExpVector())) { // TODO: avoid if possible
115                        logger.info("degree not descending: S = " + S + ", Sp = " + Sp);
116                        R = R.multiply(c);
117                        //S = S.multiply(c);
118                        Sp = S.scaleSubtractMultiple(c, a, f, p[i]);
119                    }
120                    S = Sp;                    
121                } else {
122                    R = R.multiply(c);
123                    //S = S.multiply(c);
124                    S = S.scaleSubtractMultiple(c, a, f, p[i]);
125                }
126                //Q = p[i].multiply(a, e);
127                //S = S.subtract(Q);
128            }
129        }
130        return R;
131    }
132
133
134    /**
135     * Normalform recursive.
136     * @param Ap recursive polynomial.
137     * @param Pp recursive polynomial list.
138     * @return nf(Ap) with respect to Pp.
139     */
140    @SuppressWarnings("unchecked")
141    public GenPolynomial<GenPolynomial<C>> normalformRecursive(List<GenPolynomial<GenPolynomial<C>>> Pp,
142                    GenPolynomial<GenPolynomial<C>> Ap) {
143        if (Pp == null || Pp.isEmpty()) {
144            return Ap;
145        }
146        if (Ap == null || Ap.isZERO()) {
147            return Ap;
148        }
149        Map.Entry<ExpVector, GenPolynomial<C>> m;
150        GenPolynomial<GenPolynomial<C>>[] P = new GenPolynomial[0];
151        synchronized (Pp) {
152            P = Pp.toArray(P);
153        }
154        int l = P.length;
155        ExpVector[] htl = new ExpVector[l];
156        GenPolynomial<C>[] lbc = (GenPolynomial<C>[]) new GenPolynomial[l];
157        GenPolynomial<GenPolynomial<C>>[] p = new GenPolynomial[l];
158        int i;
159        int j = 0;
160        for (i = 0; i < l; i++) {
161            if (P[i] == null) {
162                continue;
163            }
164            p[i] = P[i];
165            m = p[i].leadingMonomial();
166            if (m != null) {
167                p[j] = p[i];
168                htl[j] = m.getKey();
169                lbc[j] = m.getValue();
170                j++;
171            }
172        }
173        l = j;
174        ExpVector e, f;
175        GenPolynomial<C> a, b;
176        boolean mt = false;
177        GenPolynomial<GenPolynomial<C>> R = Ap.ring.getZERO().copy();
178
179        GenPolynomial<GenPolynomial<C>> S = Ap.copy();
180        while (S.length() > 0) {
181            m = S.leadingMonomial();
182            e = m.getKey();
183            a = m.getValue();
184            for (i = 0; i < l; i++) {
185                mt = e.multipleOf(htl[i]);
186                if (mt)
187                    break;
188            }
189            if (!mt) {
190                //logger.debug("irred");
191                //R = R.sum(a, e);
192                //S = S.subtract(a, e);
193                R.doPutToMap(e, a);
194                S.doRemoveFromMap(e, a);
195                //System.out.println(" S = " + S);
196            } else {
197                f = e.subtract(htl[i]);
198                if (debug) {
199                    logger.info("red div = " + f);
200                    //logger.info("red a = " + a);
201                }
202                GenPolynomial<C> c = (GenPolynomial<C>) lbc[i];
203                //if (a.remainder(c).isZERO()) { //c.isUnit() ) {
204                if (PolyUtil.<C> baseSparsePseudoRemainder(a, c).isZERO()) { //c.isUnit() ) {
205                    if (debug) {
206                        logger.info("red c = " + c);
207                    }
208                    //a = a.divide(c);
209                    b = PolyUtil.<C> basePseudoDivide(a, c);
210                    GenPolynomial<GenPolynomial<C>> Sp = S.subtractMultiple(b, f, p[i]);
211                    if (e.equals(Sp.leadingExpVector())) { // TODO: avoid if possible
212                        //throw new RuntimeException("degree not descending");
213                        logger.info("degree not descending: S = " + S + ", Sp = " + Sp);
214                        R = R.multiply(c);
215                        //S = S.multiply(c);
216                        Sp = S.scaleSubtractMultiple(c, a, f, p[i]);
217                    }
218                    S = Sp;
219                } else {
220                    R = R.multiply(c);
221                    //S = S.multiply(c);
222                    S = S.scaleSubtractMultiple(c, a, f, p[i]);
223                }
224                //Q = p[i].multiply(a, e);
225                //S = S.subtract(Q);
226            }
227        }
228        return R;
229    }
230
231
232    /**
233     * Normalform with recording. <b>Note:</b> Only meaningful if all divisions
234     * are exact. Compute first the multiplication factor <code>m</code> with
235     * <code>normalform(Pp,Ap,m)</code>, then call this method with
236     * <code>normalform(row,Pp,m*Ap)</code>.
237     * @param row recording matrix, is modified.
238     * @param Pp a polynomial list for reduction.
239     * @param Ap a polynomial.
240     * @return nf(Pp,Ap), the normal form of Ap wrt. Pp.
241     */
242    @SuppressWarnings("unchecked")
243    public GenPolynomial<C> normalform(List<GenPolynomial<C>> row, List<GenPolynomial<C>> Pp,
244                    GenPolynomial<C> Ap) {
245        if (Pp == null || Pp.isEmpty()) {
246            return Ap;
247        }
248        if (Ap == null || Ap.isZERO()) {
249            return Ap;
250        }
251        GenPolynomial<C>[] P = new GenPolynomial[0];
252        synchronized (Pp) {
253            P = Pp.toArray(P);
254        }
255        int l = P.length;
256        ExpVector[] htl = new ExpVector[l];
257        Object[] lbc = new Object[l]; // want C 
258        GenPolynomial<C>[] p = new GenPolynomial[l];
259        Map.Entry<ExpVector, C> m;
260        int j = 0;
261        int i;
262        for (i = 0; i < l; i++) {
263            p[i] = P[i];
264            m = p[i].leadingMonomial();
265            if (m != null) {
266                p[j] = p[i];
267                htl[j] = m.getKey();
268                lbc[j] = m.getValue();
269                j++;
270            }
271        }
272        l = j;
273        ExpVector e;
274        C a;
275        boolean mt = false;
276        GenPolynomial<C> zero = Ap.ring.getZERO();
277        GenPolynomial<C> R = Ap.ring.getZERO().copy();
278        GenPolynomial<C> fac = null;
279        GenPolynomial<C> S = Ap.copy();
280        while (S.length() > 0) {
281            m = S.leadingMonomial();
282            e = m.getKey();
283            a = m.getValue();
284            for (i = 0; i < l; i++) {
285                mt = e.multipleOf(htl[i]);
286                if (mt)
287                    break;
288            }
289            if (!mt) {
290                //logger.debug("irred");
291                //R = R.sum(a, e);
292                //S = S.subtract(a, e);
293                R.doPutToMap(e, a);
294                S.doRemoveFromMap(e, a);
295                // System.out.println(" S = " + S);
296            } else {
297                e = e.subtract(htl[i]);
298                //logger.info("red div = " + e);
299                C c = (C) lbc[i];
300                if (a.remainder(c).isZERO()) { //c.isUnit() ) {
301                    a = a.divide(c);
302                    S = S.subtractMultiple(a, e, p[i]);
303                    //System.out.print("|");
304                } else {
305                    //System.out.print("*");
306                    R = R.multiply(c);
307                    //S = S.multiply(c);
308                    S = S.scaleSubtractMultiple(c, a, e, p[i]);
309                }
310                //Q = p[i].multiply(a, e);
311                //S = S.subtract(Q);
312                fac = row.get(i);
313                if (fac == null) {
314                    fac = zero.sum(a, e);
315                } else {
316                    fac = fac.sum(a, e);
317                }
318                row.set(i, fac);
319            }
320        }
321        return R;
322    }
323
324
325    /**
326     * Normalform.
327     * @param Pp polynomial list.
328     * @param Ap polynomial.
329     * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor
330     *         for Ap.
331     */
332    @SuppressWarnings("unchecked")
333    public PseudoReductionEntry<C> normalformFactor(List<GenPolynomial<C>> Pp, GenPolynomial<C> Ap) {
334        if (Ap == null) {
335            return null;
336        }
337        C mfac = Ap.ring.getONECoefficient();
338        PseudoReductionEntry<C> pf = new PseudoReductionEntry<C>(Ap, mfac);
339        if (Pp == null || Pp.isEmpty()) {
340            return pf;
341        }
342        if (Ap.isZERO()) {
343            return pf;
344        }
345        Map.Entry<ExpVector, C> m;
346        GenPolynomial<C>[] P = new GenPolynomial[0];
347        synchronized (Pp) {
348            P = Pp.toArray(P);
349        }
350        int l = P.length;
351        ExpVector[] htl = new ExpVector[l];
352        C[] lbc = (C[]) new RingElem[l]; // want C[] 
353        GenPolynomial<C>[] p = new GenPolynomial[l];
354        int i;
355        int j = 0;
356        for (i = 0; i < l; i++) {
357            if (P[i] == null) {
358                continue;
359            }
360            p[i] = P[i];
361            m = p[i].leadingMonomial();
362            if (m != null) {
363                p[j] = p[i];
364                htl[j] = m.getKey();
365                lbc[j] = m.getValue();
366                j++;
367            }
368        }
369        l = j;
370        ExpVector e;
371        C a;
372        boolean mt = false;
373        GenPolynomial<C> R = Ap.ring.getZERO().copy();
374
375        GenPolynomial<C> S = Ap.copy();
376        while (S.length() > 0) {
377            m = S.leadingMonomial();
378            e = m.getKey();
379            a = m.getValue();
380            for (i = 0; i < l; i++) {
381                mt = e.multipleOf(htl[i]);
382                if (mt)
383                    break;
384            }
385            if (!mt) {
386                //logger.debug("irred");
387                //R = R.sum(a, e);
388                //S = S.subtract(a, e);
389                R.doPutToMap(e, a);
390                S.doRemoveFromMap(e, a);
391                //System.out.println(" S = " + S);
392            } else {
393                e = e.subtract(htl[i]);
394                //logger.info("red div = " + e);
395                C c = lbc[i];
396                if (a.remainder(c).isZERO()) { //c.isUnit() ) {
397                    a = a.divide(c);
398                    S = S.subtractMultiple(a, e, p[i]);
399                } else {
400                    mfac = mfac.multiply(c);
401                    R = R.multiply(c);
402                    //S = S.multiply(c);
403                    S = S.scaleSubtractMultiple(c, a, e, p[i]);
404                }
405                //Q = p[i].multiply(a, e);
406                //S = S.subtract(Q);
407            }
408        }
409        if (logger.isInfoEnabled()) {
410            logger.info("multiplicative factor = " + mfac);
411        }
412        pf = new PseudoReductionEntry<C>(R, mfac);
413        return pf;
414    }
415
416}