001/*
002 * $Id: Residue.java 5934 2018-09-30 11:23:44Z kredel $
003 */
004
005package edu.jas.poly;
006
007
008import org.apache.logging.log4j.Logger;
009import org.apache.logging.log4j.LogManager; 
010
011import edu.jas.structure.GcdRingElem;
012import edu.jas.structure.NotInvertibleException;
013import edu.jas.structure.RingElem;
014
015
016/**
017 * Residue element based on RingElem residue. Objects of this class are (nearly)
018 * immutable.
019 * @author Heinz Kredel
020 */
021public class Residue<C extends RingElem<C>> implements RingElem<Residue<C>> {
022
023
024    private static final Logger logger = LogManager.getLogger(Residue.class);
025
026
027    private static final boolean debug = logger.isDebugEnabled();
028
029
030    /**
031     * Residue class factory data structure.
032     */
033    protected final ResidueRing<C> ring;
034
035
036    /**
037     * Value part of the element data structure.
038     */
039    protected final C val;
040
041
042    /**
043     * Flag to remember if this residue element is a unit. -1 is unknown, 1 is
044     * unit, 0 not a unit.
045     */
046    protected int isunit = -1; // initially unknown
047
048
049    /**
050     * The constructor creates a Residue object from a ring factory.
051     * @param r ring factory.
052     */
053    public Residue(ResidueRing<C> r) {
054        this(r, r.ring.getZERO(), 0);
055    }
056
057
058    /**
059     * The constructor creates a Residue object from a ring factory and a ring
060     * element.
061     * @param r ring factory.
062     * @param a ring element.
063     */
064    public Residue(ResidueRing<C> r, C a) {
065        this(r, a, -1);
066    }
067
068
069    /**
070     * The constructor creates a Residue object from a ring factory, a ring
071     * element and an indicator if a is a unit.
072     * @param r ring factory.
073     * @param a ring element.
074     * @param u isunit indicator, -1, 0, 1.
075     */
076    public Residue(ResidueRing<C> r, C a, int u) {
077        ring = r;
078        C v = a.remainder(ring.modul);
079        if (v.signum() < 0) {
080            v = v.sum(ring.modul);
081        }
082        val = v;
083        if (u == 0 || u == 1) {
084            isunit = u;
085            return;
086        }
087        if (val.isZERO()) {
088            isunit = 0;
089            return;
090        }
091        if (val.isUnit()) {
092            isunit = 1;
093            //} else { // not possible
094            //isunit = 0;
095        }
096        isunit = -1;
097    }
098
099
100    /**
101     * Get the corresponding element factory.
102     * @return factory for this Element.
103     * @see edu.jas.structure.Element#factory()
104     */
105    public ResidueRing<C> factory() {
106        return ring;
107    }
108
109
110    /**
111     * Copy this.
112     * @see edu.jas.structure.Element#copy()
113     */
114    @Override
115    public Residue<C> copy() {
116        return new Residue<C>(ring, val);
117    }
118
119
120    /**
121     * Is Residue zero.
122     * @return If this is 0 then true is returned, else false.
123     * @see edu.jas.structure.RingElem#isZERO()
124     */
125    public boolean isZERO() {
126        return val.equals(ring.ring.getZERO());
127    }
128
129
130    /**
131     * Is Residue one.
132     * @return If this is 1 then true is returned, else false.
133     * @see edu.jas.structure.RingElem#isONE()
134     */
135    public boolean isONE() {
136        return val.equals(ring.ring.getONE());
137    }
138
139
140    /**
141     * Is Residue unit.
142     * @return If this is a unit then true is returned, else false.
143     * @see edu.jas.structure.RingElem#isUnit()
144     */
145    @SuppressWarnings("unchecked")
146    public boolean isUnit() {
147        if (isunit == 1) {
148            return true;
149        }
150        if (isunit == 0) {
151            return false;
152        }
153        // val.isUnit() already tested
154        // not jet known
155        if (val instanceof GcdRingElem && ring.modul instanceof GcdRingElem) {
156            GcdRingElem v = (GcdRingElem) val;
157            GcdRingElem m = (GcdRingElem) ring.modul;
158            C gcd = (C) v.gcd(m);
159            if (debug) {
160                logger.info("gcd = " + gcd);
161            }
162            boolean u = gcd.isONE();
163            if (u) {
164                isunit = 1;
165            } else {
166                isunit = 0;
167            }
168            return u;
169        }
170        // still unknown
171        return false;
172    }
173
174
175    /**
176     * Get the String representation as RingElem.
177     * @see java.lang.Object#toString()
178     */
179    @Override
180    public String toString() {
181        return "Residue[ " + val.toString() + " mod " + ring.toString() + " ]";
182    }
183
184
185    /**
186     * Get a scripting compatible string representation.
187     * @return script compatible representation for this Element.
188     * @see edu.jas.structure.Element#toScript()
189     */
190    @Override
191    public String toScript() {
192        // Python case
193        return "Residue( " + val.toScript() + " , " + ring.toScript() + " )";
194    }
195
196
197    /**
198     * Get a scripting compatible string representation of the factory.
199     * @return script compatible representation for this ElemFactory.
200     * @see edu.jas.structure.Element#toScriptFactory()
201     */
202    @Override
203    public String toScriptFactory() {
204        // Python case
205        return factory().toScript();
206    }
207
208
209    /**
210     * Residue comparison.
211     * @param b Residue.
212     * @return sign(this-b), 0 means that this and b are equivalent in this
213     *         residue class ring.
214     */
215    @Override
216    public int compareTo(Residue<C> b) {
217        C v = b.val;
218        if (!ring.equals(b.ring)) {
219            v = v.remainder(ring.modul);
220        }
221        return val.compareTo(v);
222    }
223
224
225    /**
226     * Comparison with any other object.
227     * @see java.lang.Object#equals(java.lang.Object)
228     * @return true means that this and b are equivalent in this residue class
229     *         ring.
230     */
231    @Override
232    @SuppressWarnings("unchecked")
233    public boolean equals(Object b) {
234        if (b == null) {
235            return false;
236        }
237        if (!(b instanceof Residue)) {
238            return false;
239        }
240        Residue<C> a = (Residue<C>) b;
241        return (0 == compareTo(a));
242    }
243
244
245    /**
246     * Hash code for this local.
247     * @see java.lang.Object#hashCode()
248     */
249    @Override
250    public int hashCode() {
251        int h;
252        h = ring.hashCode();
253        h = 37 * h + val.hashCode();
254        return h;
255    }
256
257
258    /**
259     * Residue absolute value.
260     * @return the absolute value of this.
261     * @see edu.jas.structure.RingElem#abs()
262     */
263    public Residue<C> abs() {
264        return new Residue<C>(ring, val.abs());
265    }
266
267
268    /**
269     * Residue summation.
270     * @param S Residue.
271     * @return this+S.
272     */
273    public Residue<C> sum(Residue<C> S) {
274        return new Residue<C>(ring, val.sum(S.val));
275    }
276
277
278    /**
279     * Residue negate.
280     * @return -this.
281     * @see edu.jas.structure.RingElem#negate()
282     */
283    public Residue<C> negate() {
284        return new Residue<C>(ring, val.negate());
285    }
286
287
288    /**
289     * Residue signum.
290     * @see edu.jas.structure.RingElem#signum()
291     * @return signum(this).
292     */
293    public int signum() {
294        return val.signum();
295    }
296
297
298    /**
299     * Residue subtraction.
300     * @param S Residue.
301     * @return this-S.
302     */
303    public Residue<C> subtract(Residue<C> S) {
304        return new Residue<C>(ring, val.subtract(S.val));
305    }
306
307
308    /**
309     * Residue division.
310     * @param S Residue.
311     * @return this/S.
312     */
313    public Residue<C> divide(Residue<C> S) {
314        return multiply(S.inverse());
315    }
316
317
318    /**
319     * Residue inverse.
320     * @see edu.jas.structure.RingElem#inverse()
321     * @return S with S = 1/this if defined.
322     */
323    @SuppressWarnings("unchecked")
324    public Residue<C> inverse() {
325        if (isunit == 0) {
326            throw new NotInvertibleException("element not invertible (0) " + this);
327        }
328        if (val instanceof GcdRingElem && ring.modul instanceof GcdRingElem) {
329            GcdRingElem v = (GcdRingElem) val;
330            GcdRingElem m = (GcdRingElem) ring.modul;
331            C[] egcd = (C[]) v.egcd(m);
332            if (debug) {
333                logger.info("egcd = " + egcd[0] + ", f = " + egcd[1]);
334            }
335            if (!egcd[0].isONE()) {
336                isunit = 0;
337                throw new NotInvertibleException("element not invertible (gcd)" + this);
338            }
339            isunit = 1;
340            C x = egcd[1];
341            return new Residue<C>(ring, x);
342        }
343        if (val.isUnit()) {
344            C x = val.inverse();
345            return new Residue<C>(ring, x);
346        }
347        System.out.println("isunit = " + isunit + ", isUnit() = " + this.isUnit());
348        throw new NotInvertibleException("element not invertible (!gcd)" + this);
349    }
350
351
352    /**
353     * Residue remainder.
354     * @param S Residue.
355     * @return this - (this/S)*S.
356     */
357    public Residue<C> remainder(Residue<C> S) {
358        C x = val.remainder(S.val);
359        return new Residue<C>(ring, x);
360    }
361
362
363    /**
364     * Quotient and remainder by division of this by S.
365     * @param S a Residue
366     * @return [this/S, this - (this/S)*S].
367     */
368    @SuppressWarnings("unchecked")
369    public Residue<C>[] quotientRemainder(Residue<C> S) {
370        return new Residue[] { divide(S), remainder(S) };
371    }
372
373
374    /**
375     * Residue multiplication.
376     * @param S Residue.
377     * @return this*S.
378     */
379    public Residue<C> multiply(Residue<C> S) {
380        return new Residue<C>(ring, val.multiply(S.val));
381    }
382
383
384    /**
385     * Greatest common divisor. <b>Note: </b>Not implemented, throws
386     * UnsupportedOperationException.
387     * @param b other element.
388     * @return gcd(this,b).
389     */
390    public Residue<C> gcd(Residue<C> b) {
391        throw new UnsupportedOperationException("gcd not implemented " + this.getClass().getName());
392    }
393
394
395    /**
396     * Extended greatest common divisor. <b>Note: </b>Not implemented, throws
397     * UnsupportedOperationException.
398     * @param b other element.
399     * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b).
400     */
401    public Residue<C>[] egcd(Residue<C> b) {
402        throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName());
403    }
404
405}