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