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