001/*
002 * $Id: MultiplicativeSet.java 4061 2012-07-27 12:03:20Z kredel $
003 */
004
005package edu.jas.gbufd;
006
007
008import java.io.Serializable;
009import java.util.ArrayList;
010import java.util.List;
011
012import org.apache.log4j.Logger;
013
014import edu.jas.poly.GenPolynomial;
015import edu.jas.poly.GenPolynomialRing;
016import edu.jas.structure.GcdRingElem;
017
018
019/**
020 * Multiplicative set of polynomials. a, b in M implies a*b in M, 1 in M.
021 * @param <C> coefficient type
022 * @author Heinz Kredel.
023 */
024public class MultiplicativeSet<C extends GcdRingElem<C>> implements Serializable {
025
026
027    private static final Logger logger = Logger.getLogger(MultiplicativeSet.class);
028
029
030    //private final boolean debug = logger.isDebugEnabled();
031
032
033    /**
034     * Data structure.
035     */
036    public final List<GenPolynomial<C>> mset;
037
038
039    /**
040     * Polynomial ring factory.
041     */
042    public final GenPolynomialRing<C> ring;
043
044
045    /**
046     * MultiplicativeSet constructor. Constructs an empty multiplicative set.
047     * @param ring polynomial ring factory for coefficients.
048     */
049    public MultiplicativeSet(GenPolynomialRing<C> ring) {
050        this(ring, new ArrayList<GenPolynomial<C>>());
051        if (ring == null) {
052            throw new IllegalArgumentException("only for non null rings");
053        }
054    }
055
056
057    /**
058     * MultiplicativeSet constructor.
059     * @param ring polynomial ring factory for coefficients.
060     * @param ms a list of non-zero polynomials.
061     */
062    protected MultiplicativeSet(GenPolynomialRing<C> ring, List<GenPolynomial<C>> ms) {
063        if (ms == null || ring == null) {
064            throw new IllegalArgumentException("only for non null parts");
065        }
066        this.ring = ring;
067        mset = ms;
068    }
069
070
071    /**
072     * toString.
073     * @see java.lang.Object#toString()
074     */
075    @Override
076    public String toString() {
077        return "MultiplicativeSet" + mset;
078    }
079
080
081    /**
082     * Equals.
083     * @param ob an Object.
084     * @return true if this is equal to o, else false.
085     */
086    @Override
087    @SuppressWarnings("unchecked")
088    public boolean equals(Object ob) {
089        MultiplicativeSet<C> c = null;
090        try {
091            c = (MultiplicativeSet<C>) ob;
092        } catch (ClassCastException e) {
093            return false;
094        }
095        if (c == null) {
096            return false;
097        }
098        if (!ring.equals(c.ring)) {
099            return false;
100        }
101        return mset.equals(c.mset);
102    }
103
104
105    /**
106     * Hash code for this condition.
107     * @see java.lang.Object#hashCode()
108     */
109    @Override
110    public int hashCode() {
111        int h;
112        h = ring.hashCode();
113        h = h << 17;
114        h += mset.hashCode();
115        return h;
116    }
117
118
119    /**
120     * Is set.
121     * @return true if this is the empty set, else false.
122     */
123    public boolean isEmpty() {
124        return mset.size() == 0;
125    }
126
127
128    /**
129     * Test if a polynomial is contained in this multiplicative set.
130     * @param c polynomial searched in mset.
131     * @return true, if c = prod_{m in mset} m, else false
132     */
133    public boolean contains(GenPolynomial<C> c) {
134        if (c == null || c.isZERO()) {
135            return false;
136        }
137        if (c.isConstant()) {
138            return true;
139        }
140        if (mset.isEmpty()) {
141            return false;
142        }
143        GenPolynomial<C> d = c;
144        for (GenPolynomial<C> n : mset) {
145            // System.out.println("mset n = " + n);
146            if (n.isONE()) { // do not use 1
147                continue;
148            }
149            GenPolynomial<C> q, r;
150            do {
151                GenPolynomial<C>[] qr = d.quotientRemainder(n);
152                q = qr[0];
153                r = qr[1];
154                // System.out.println("q = " + q + ", r = " + r + ", d = " + d +
155                // ", n = " + n);
156                if (!r.isZERO()) {
157                    continue;
158                }
159                if (q.isConstant()) {
160                    return true;
161                }
162                d = q;
163            } while (r.isZERO() && !d.isConstant());
164        }
165        return d.isConstant(); // false
166    }
167
168
169    /**
170     * Test if a list of polynomials is contained in multiplicative set.
171     * @param L list of polynomials to be searched in mset.
172     * @return true, if all c in L are in mset, else false
173     */
174    public boolean contains(List<GenPolynomial<C>> L) {
175        if (L == null || L.size() == 0) {
176            return true;
177        }
178        for (GenPolynomial<C> c : L) {
179            if (!contains(c)) {
180                return false;
181            }
182        }
183        return true;
184    }
185
186
187    /**
188     * Add polynomial to mset.
189     * @param cc polynomial to be added to mset.
190     * @return new multiplicative set. <b>Note:</b> must be overridden in
191     *         sub-classes.
192     */
193    public MultiplicativeSet<C> add(GenPolynomial<C> cc) {
194        if (cc == null || cc.isZERO() || cc.isConstant()) {
195            return this;
196        }
197        if (ring.coFac.isField()) {
198            cc = cc.monic();
199        }
200        List<GenPolynomial<C>> list;
201        if (mset.size() == 0) {
202            list = new ArrayList<GenPolynomial<C>>(1);
203            list.add(cc);
204            return new MultiplicativeSet<C>(ring, list);
205        }
206        GenPolynomial<C> c = removeFactors(cc);
207        if (c.isConstant()) {
208            logger.info("skipped unit or constant = " + c);
209            return this;
210        }
211        if (ring.coFac.isField()) {
212            c = c.monic();
213        }
214        if (mset.size() == 0) {
215            logger.info("added to empty mset = " + c);
216        } else {
217            logger.info("added to mset = " + c);
218        }
219        list = new ArrayList<GenPolynomial<C>>(mset);
220        list.add(c);
221        return new MultiplicativeSet<C>(ring, list);
222    }
223
224
225    /**
226     * Replace polynomial list of mset.
227     * @param L polynomial list to replace mset.
228     * @return new multiplicative set. <b>Note:</b> must be overridden in
229     *         sub-classes.
230     */
231    public MultiplicativeSet<C> replace(List<GenPolynomial<C>> L) {
232        MultiplicativeSet<C> ms = new MultiplicativeSet<C>(ring);
233        if (L == null || L.size() == 0) {
234            return ms;
235        }
236        for (GenPolynomial<C> p : L) {
237            ms = ms.add(p);
238        }
239        return ms;
240    }
241
242
243    /**
244     * Remove factors by mset factors division.
245     * @param cc polynomial to be removed factors from mset.
246     * @return quotient polynomial.
247     */
248    public GenPolynomial<C> removeFactors(GenPolynomial<C> cc) {
249        if (cc == null || cc.isZERO() || cc.isConstant()) {
250            return cc;
251        }
252        if (mset.size() == 0) {
253            return cc;
254        }
255        GenPolynomial<C> c = cc;
256        for (GenPolynomial<C> n : mset) {
257            if (n.isConstant()) { // do not use 1, should not be in mset
258                continue;
259            }
260            GenPolynomial<C> q, r;
261            do {
262                GenPolynomial<C>[] qr = c.quotientRemainder(n);
263                q = qr[0];
264                r = qr[1];
265                if (r != null && !r.isZERO()) {
266                    continue;
267                }
268                if (q != null && q.isConstant()) {
269                    return q;
270                }
271                c = q;
272            } while (r.isZERO() && !c.isConstant());
273        }
274        return c;
275    }
276
277
278    /**
279     * Remove factors by mset factors division.
280     * @param L list of polynomial to be removed factors from mset.
281     * @return quotient polynomial list.
282     */
283    public List<GenPolynomial<C>> removeFactors(List<GenPolynomial<C>> L) {
284        if (L == null || L.size() == 0) {
285            return L;
286        }
287        if (mset.size() == 0) {
288            return L;
289        }
290        List<GenPolynomial<C>> M = new ArrayList<GenPolynomial<C>>(L.size());
291        for (GenPolynomial<C> p : L) {
292            p = removeFactors(p);
293            // nono, really: if ( !p.isConstant() ) {
294            M.add(p);
295        }
296        return M;
297    }
298
299}