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