001/*
002 * $Id: LocalRing.java 4679 2013-10-27 13:19:41Z kredel $
003 */
004
005package edu.jas.application;
006
007
008import java.io.Reader;
009import java.util.ArrayList;
010import java.util.List;
011import java.util.Random;
012
013import org.apache.log4j.Logger;
014
015import edu.jas.kern.StringUtil;
016import edu.jas.poly.GenPolynomial;
017import edu.jas.poly.GenPolynomialRing;
018import edu.jas.structure.GcdRingElem;
019import edu.jas.structure.RingFactory;
020import edu.jas.ufd.GCDFactory;
021import edu.jas.ufd.GreatestCommonDivisor;
022import edu.jas.structure.QuotPairFactory;
023
024
025/**
026 * Local ring class based on GenPolynomial with RingElem interface. Objects of
027 * this class are effective immutable.
028 * @author Heinz Kredel
029 */
030public class LocalRing<C extends GcdRingElem<C>> 
031       implements RingFactory<Local<C>>, QuotPairFactory<GenPolynomial<C>,Local<C>>  {
032
033
034    private static final Logger logger = Logger.getLogger(LocalRing.class);
035
036
037    //private boolean debug = logger.isDebugEnabled();
038
039
040    /**
041     * Greatest common divisor engine for coefficient content and primitive
042     * parts.
043     */
044    protected final GreatestCommonDivisor<C> engine;
045
046
047    /**
048     * Polynomial ideal for localization.
049     */
050    public final Ideal<C> ideal;
051
052
053    /**
054     * Polynomial ring of the factory.
055     */
056    public final GenPolynomialRing<C> ring;
057
058
059    /**
060     * Indicator if this ring is a field.
061     */
062    protected int isField = -1; // initially unknown
063
064
065    /**
066     * The constructor creates a LocalRing object from an Ideal.
067     * @param i localization polynomial ideal.
068     */
069    public LocalRing(Ideal<C> i) {
070        if (i == null) {
071            throw new IllegalArgumentException("ideal may not be null");
072        }
073        ideal = i.GB(); // cheap if isGB
074        if (ideal.isONE()) {
075            throw new IllegalArgumentException("ideal may not be 1");
076        }
077        if (ideal.isMaximal()) {
078            isField = 1;
079        } else {
080            isField = 0;
081            logger.warn("ideal not maximal");
082            //throw new IllegalArgumentException("ideal must be maximal");
083        }
084        ring = ideal.list.ring;
085        //engine = GCDFactory.<C>getImplementation( ring.coFac );
086        engine = GCDFactory.<C> getProxy(ring.coFac);
087    }
088
089
090    /**
091     * Factory for base elements.
092     */
093    public GenPolynomialRing<C> pairFactory() {
094        return ring;
095    }
096
097
098    /**
099     * Create from numerator.
100     */
101    public Local<C> create(GenPolynomial<C> n) {
102        return new Local<C>(this, n);
103    }
104
105
106    /**
107     * Create from numerator, denominator pair.
108     */
109    public Local<C> create(GenPolynomial<C> n, GenPolynomial<C> d) {
110        return new Local<C>(this, n, d);
111    }
112
113
114    /**
115     * Is this structure finite or infinite.
116     * @return true if this structure is finite, else false.
117     * @see edu.jas.structure.ElemFactory#isFinite()
118     */
119    public boolean isFinite() {
120        return ring.isFinite() && ideal.bb.commonZeroTest(ideal.getList()) <= 0;
121    }
122
123
124    /**
125     * Copy Local element c.
126     * @param c
127     * @return a copy of c.
128     */
129    public Local<C> copy(Local<C> c) {
130        return new Local<C>(c.ring, c.num, c.den, true);
131    }
132
133
134    /**
135     * Get the zero element.
136     * @return 0 as Local.
137     */
138    public Local<C> getZERO() {
139        return new Local<C>(this, ring.getZERO());
140    }
141
142
143    /**
144     * Get the one element.
145     * @return 1 as Local.
146     */
147    public Local<C> getONE() {
148        return new Local<C>(this, ring.getONE());
149    }
150
151
152    /**
153     * Get a list of the generating elements.
154     * @return list of generators for the algebraic structure.
155     * @see edu.jas.structure.ElemFactory#generators()
156     */
157    public List<Local<C>> generators() {
158        List<GenPolynomial<C>> pgens = ring.generators();
159        List<Local<C>> gens = new ArrayList<Local<C>>(pgens.size());
160        GenPolynomial<C> one = ring.getONE();
161        for (GenPolynomial<C> p : pgens) {
162            Local<C> q = new Local<C>(this, p);
163            gens.add(q);
164            if (!p.isONE() && !ideal.contains(p)) { // q.isUnit()
165                q = new Local<C>(this, one, p);
166                gens.add(q);
167            }
168        }
169        return gens;
170    }
171
172
173    /**
174     * Query if this ring is commutative.
175     * @return true if this ring is commutative, else false.
176     */
177    public boolean isCommutative() {
178        return ring.isCommutative();
179    }
180
181
182    /**
183     * Query if this ring is associative.
184     * @return true if this ring is associative, else false.
185     */
186    public boolean isAssociative() {
187        return ring.isAssociative();
188    }
189
190
191    /**
192     * Query if this ring is a field.
193     * @return false.
194     */
195    public boolean isField() {
196        if (isField > 0) {
197            return true;
198        }
199        if (isField == 0) {
200            return false;
201        }
202        // not reached
203        return false;
204    }
205
206
207    /**
208     * Characteristic of this ring.
209     * @return characteristic of this ring.
210     */
211    public java.math.BigInteger characteristic() {
212        return ring.characteristic();
213    }
214
215
216    /**
217     * Get a Local element from a BigInteger value.
218     * @param a BigInteger.
219     * @return a Local.
220     */
221    public Local<C> fromInteger(java.math.BigInteger a) {
222        return new Local<C>(this, ring.fromInteger(a));
223    }
224
225
226    /**
227     * Get a Local element from a long value.
228     * @param a long.
229     * @return a Local.
230     */
231    public Local<C> fromInteger(long a) {
232        return new Local<C>(this, ring.fromInteger(a));
233    }
234
235
236    /**
237     * Get the String representation as RingFactory.
238     * @see java.lang.Object#toString()
239     */
240    @Override
241    public String toString() {
242        return "LocalRing[ " + ideal.toString() + " ]";
243    }
244
245
246    /**
247     * Get a scripting compatible string representation.
248     * @return script compatible representation for this ElemFactory.
249     * @see edu.jas.structure.ElemFactory#toScript()
250     */
251    @Override
252    public String toScript() {
253        // Python case
254        return "LC(" + ideal.list.toScript() + ")";
255    }
256
257
258    /**
259     * Comparison with any other object.
260     * @see java.lang.Object#equals(java.lang.Object)
261     */
262    @Override
263    @SuppressWarnings("unchecked")
264    // not jet working
265    public boolean equals(Object b) {
266        if (!(b instanceof LocalRing)) {
267            return false;
268        }
269        LocalRing<C> a = null;
270        try {
271            a = (LocalRing<C>) b;
272        } catch (ClassCastException e) {
273        }
274        if (a == null) {
275            return false;
276        }
277        if (!ring.equals(a.ring)) {
278            return false;
279        }
280        return ideal.equals(a.ideal);
281    }
282
283
284    /**
285     * Hash code for this local ring.
286     * @see java.lang.Object#hashCode()
287     */
288    @Override
289    public int hashCode() {
290        int h;
291        h = ideal.hashCode();
292        return h;
293    }
294
295
296    /**
297     * Local random.
298     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
299     * @return a random residue element.
300     */
301    public Local<C> random(int n) {
302        GenPolynomial<C> r = ring.random(n).monic();
303        r = ideal.normalform(r);
304        GenPolynomial<C> s;
305        do {
306            s = ring.random(n).monic();
307            s = ideal.normalform(s);
308        } while (s.isZERO());
309        return new Local<C>(this, r, s, false);
310    }
311
312
313    /**
314     * Generate a random residum polynomial.
315     * @param k bitsize of random coefficients.
316     * @param l number of terms.
317     * @param d maximal degree in each variable.
318     * @param q density of nozero exponents.
319     * @return a random residue polynomial.
320     */
321    public Local<C> random(int k, int l, int d, float q) {
322        GenPolynomial<C> r = ring.random(k, l, d, q).monic();
323        r = ideal.normalform(r);
324        GenPolynomial<C> s;
325        do {
326            s = ring.random(k, l, d, q).monic();
327            s = ideal.normalform(s);
328        } while (s.isZERO());
329        return new Local<C>(this, r, s, false);
330    }
331
332
333    /**
334     * Local random.
335     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
336     * @param rnd is a source for random bits.
337     * @return a random residue element.
338     */
339    public Local<C> random(int n, Random rnd) {
340        GenPolynomial<C> r = ring.random(n, rnd).monic();
341        r = ideal.normalform(r);
342        GenPolynomial<C> s;
343        do {
344            s = ring.random(n).monic();
345            s = ideal.normalform(s);
346        } while (s.isZERO());
347        return new Local<C>(this, r, s, false);
348    }
349
350
351    /**
352     * Parse Local from String.
353     * @param s String.
354     * @return Local from s.
355     */
356    public Local<C> parse(String s) {
357        int i = s.indexOf("{");
358        if (i >= 0) {
359            s = s.substring(i + 1);
360        }
361        i = s.lastIndexOf("}");
362        if (i >= 0) {
363            s = s.substring(0, i);
364        }
365        i = s.indexOf("|");
366        if (i < 0) {
367            GenPolynomial<C> n = ring.parse(s);
368            return new Local<C>(this, n);
369        }
370        String s1 = s.substring(0, i);
371        String s2 = s.substring(i + 1);
372        GenPolynomial<C> n = ring.parse(s1);
373        GenPolynomial<C> d = ring.parse(s2);
374        return new Local<C>(this, n, d);
375    }
376
377
378    /**
379     * Parse Local from Reader.
380     * @param r Reader.
381     * @return next Local from r.
382     */
383    public Local<C> parse(Reader r) {
384        String s = StringUtil.nextPairedString(r, '{', '}');
385        return parse(s);
386    }
387
388}