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