001/*
002 * $Id$
003 */
004
005package edu.jas.application;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import edu.jas.kern.PrettyPrint;
012import edu.jas.poly.GenWordPolynomial;
013import edu.jas.poly.Word;
014import edu.jas.structure.GcdRingElem;
015import edu.jas.structure.NoncomRingElem;
016import edu.jas.structure.NotDivisibleException;
017import edu.jas.structure.NotInvertibleException;
018import edu.jas.structure.QuotPair;
019import edu.jas.structure.Value;
020
021
022/**
023 * WordResidue ring element based on GenWordPolynomial with GcdRingElem
024 * interface. Objects of this class are immutable.
025 * @author Heinz Kredel
026 */
027public class WordResidue<C extends GcdRingElem<C>> implements GcdRingElem<WordResidue<C>>,
028                NoncomRingElem<WordResidue<C>>, QuotPair<GenWordPolynomial<C>>, Value<GenWordPolynomial<C>> {
029
030
031    /**
032     * WordResidue class factory data structure.
033     */
034    public final WordResidueRing<C> ring;
035
036
037    /**
038     * Value part of the element data structure.
039     */
040    public final GenWordPolynomial<C> val;
041
042
043    /**
044     * Flag to remember if this residue element is a unit. -1 is unknown, 1 is
045     * unit, 0 not a unit.
046     */
047    protected int isunit = -1; // initially unknown
048
049
050    /**
051     * The constructor creates a WordResidue object from a ring factory.
052     * @param r solvable residue ring factory.
053     */
054    public WordResidue(WordResidueRing<C> r) {
055        this(r, r.ring.getZERO(), 0);
056    }
057
058
059    /**
060     * The constructor creates a WordResidue object from a ring factory and a
061     * polynomial.
062     * @param r solvable residue ring factory.
063     * @param a solvable polynomial.
064     */
065    public WordResidue(WordResidueRing<C> r, GenWordPolynomial<C> a) {
066        this(r, a, -1);
067    }
068
069
070    /**
071     * The constructor creates a WordResidue object from a ring factory, a
072     * polynomial and an indicator if a is a unit.
073     * @param r solvable residue ring factory.
074     * @param a solvable polynomial.
075     * @param u isunit indicator, -1, 0, 1.
076     */
077    public WordResidue(WordResidueRing<C> r, GenWordPolynomial<C> a, int u) {
078        ring = r;
079        val = ring.ideal.normalform(a); //.monic() no go
080        if (u == 0 || u == 1) {
081            isunit = u;
082            return;
083        }
084        if (val.isZERO()) {
085            isunit = 0;
086            return;
087        }
088        if (ring.isField()) {
089            isunit = 1;
090            return;
091        }
092        if (val.isUnit()) {
093            isunit = 1;
094            //} else { // not possible
095            //isunit = 0;
096        }
097        isunit = -1;
098    }
099
100
101    /**
102     * Get the corresponding element factory.
103     * @return factory for this Element.
104     * @see edu.jas.structure.Element#factory()
105     */
106    public WordResidueRing<C> factory() {
107        return ring;
108    }
109
110
111    /**
112     * Value. Returns the value.
113     * @see edu.jas.structure.Value#value()
114     */
115    public GenWordPolynomial<C> value() {
116        return val;
117    }
118
119
120    /**
121     * Numerator. Returns the value.
122     * @see edu.jas.structure.QuotPair#numerator()
123     */
124    public GenWordPolynomial<C> numerator() {
125        return val;
126    }
127
128
129    /**
130     * Denominator. Returns 1.
131     * @see edu.jas.structure.QuotPair#denominator()
132     */
133    public GenWordPolynomial<C> denominator() {
134        return ring.ring.getONE();
135    }
136
137
138    /**
139     * Clone this.
140     * @see java.lang.Object#clone()
141     */
142    @Override
143    public WordResidue<C> copy() {
144        return new WordResidue<C>(ring, val, isunit);
145    }
146
147
148    /**
149     * Is WordResidue zero.
150     * @return If this is 0 then true is returned, else false.
151     * @see edu.jas.structure.RingElem#isZERO()
152     */
153    public boolean isZERO() {
154        return val.isZERO();
155    }
156
157
158    /**
159     * Is WordResidue one.
160     * @return If this is 1 then true is returned, else false.
161     * @see edu.jas.structure.RingElem#isONE()
162     */
163    public boolean isONE() {
164        return val.isONE();
165    }
166
167
168    /**
169     * Is WordResidue unit.
170     * @return If this is a unit then true is returned, else false.
171     * @see edu.jas.structure.RingElem#isUnit()
172     */
173    public boolean isUnit() {
174        if (isunit > 0) {
175            return true;
176        }
177        if (isunit == 0) {
178            return false;
179        }
180        // not jet known
181        boolean u = ring.ideal.isUnit(val);
182        //System.out.println("WordResidue.isUnit " + val);
183        if (u) {
184            isunit = 1; // seems to be wrong for solvable polynomial rings
185        } else {
186            isunit = 0;
187        }
188        return isunit > 0;
189    }
190
191
192    /**
193     * Is WordResidue a constant.
194     * @return true if this.val is a constant polynomial, else false.
195     */
196    public boolean isConstant() {
197        return val.isConstant();
198    }
199
200
201    /**
202     * Get the String representation as RingElem.
203     * @see java.lang.Object#toString()
204     */
205    @Override
206    public String toString() {
207        if (PrettyPrint.isTrue()) {
208            return val.toString();
209        }
210        return "WordResidue[ " + val.toString() + " mod " + ring.toString() + " ]";
211    }
212
213
214    /**
215     * Get a scripting compatible string representation.
216     * @return script compatible representation for this Element.
217     * @see edu.jas.structure.Element#toScript()
218     */
219    @Override
220    public String toScript() {
221        // Python case
222        return val.toScript();
223        // return "PolyWordResidue( " + val.toScript() 
224        //                         + ", " + ring.toScript() + " )";
225    }
226
227
228    /**
229     * Get a scripting compatible string representation of the factory.
230     * @return script compatible representation for this ElemFactory.
231     * @see edu.jas.structure.Element#toScriptFactory()
232     */
233    @Override
234    public String toScriptFactory() {
235        // Python case
236        return factory().toScript();
237    }
238
239
240    /**
241     * WordResidue comparison.
242     * @param b WordResidue.
243     * @return sign(this-b), 0 means that this and b are equivalent in this
244     *         residue class ring.
245     */
246    @Override
247    public int compareTo(WordResidue<C> b) {
248        GenWordPolynomial<C> v = b.val;
249        if (!ring.equals(b.ring)) {
250            v = ring.ideal.normalform(v);
251        }
252        return val.compareTo(v);
253    }
254
255
256    /**
257     * Comparison with any other object.
258     * @see java.lang.Object#equals(java.lang.Object)
259     * @return true means that this and b are equivalent in this residue class
260     *         ring.
261     */
262    @Override
263    @SuppressWarnings("unchecked")
264    public boolean equals(Object b) {
265        if (!(b instanceof WordResidue)) {
266            return false;
267        }
268        WordResidue<C> a = null;
269        try {
270            a = (WordResidue<C>) b;
271        } catch (ClassCastException e) {
272        }
273        if (a == null) {
274            return false;
275        }
276        return compareTo(a) == 0;
277    }
278
279
280    /**
281     * Hash code for this residue.
282     * @see java.lang.Object#hashCode()
283     */
284    @Override
285    public int hashCode() {
286        int h;
287        h = ring.hashCode();
288        h = 37 * h + val.hashCode();
289        return h;
290    }
291
292
293    /**
294     * WordResidue absolute value.
295     * @return the absolute value of this.
296     * @see edu.jas.structure.RingElem#abs()
297     */
298    public WordResidue<C> abs() {
299        return new WordResidue<C>(ring, val.abs(), isunit);
300    }
301
302
303    /**
304     * WordResidue summation.
305     * @param S WordResidue.
306     * @return this+S.
307     */
308    public WordResidue<C> sum(WordResidue<C> S) {
309        return new WordResidue<C>(ring, val.sum(S.val));
310    }
311
312
313    /**
314     * WordResidue negate.
315     * @return -this.
316     * @see edu.jas.structure.RingElem#negate()
317     */
318    public WordResidue<C> negate() {
319        return new WordResidue<C>(ring, val.negate(), isunit);
320    }
321
322
323    /**
324     * WordResidue signum.
325     * @see edu.jas.structure.RingElem#signum()
326     * @return signum(this).
327     */
328    public int signum() {
329        return val.signum();
330    }
331
332
333    /**
334     * WordResidue subtraction.
335     * @param S WordResidue.
336     * @return this-S.
337     */
338    public WordResidue<C> subtract(WordResidue<C> S) {
339        return new WordResidue<C>(ring, val.subtract(S.val));
340    }
341
342
343    /**
344     * WordResidue left division.
345     * @param S WordResidue.
346     * @return left, with left*S = this
347     */
348    public WordResidue<C> divide(WordResidue<C> S) {
349        if (ring.isField()) {
350            return multiply(S.inverse());
351        }
352        try {
353            return multiply(S.inverse());
354        } catch (NotInvertibleException ignored) {
355            System.out.println("catch: " + ignored);
356            //ignored.printStackTrace();
357            // ignored
358        } catch (UnsupportedOperationException ignored) {
359            //System.out.println("catch: " + ignored);
360            //ignored.printStackTrace();
361            // ignored
362        }
363        List<GenWordPolynomial<C>> L = new ArrayList<GenWordPolynomial<C>>(1);
364        L.add(ring.ring.getZERO());
365        List<GenWordPolynomial<C>> V = new ArrayList<GenWordPolynomial<C>>(1);
366        V.add(S.val);
367        //@SuppressWarnings("unused")
368        GenWordPolynomial<C> x = ring.bb.red.leftNormalform(L, V, val);
369        GenWordPolynomial<C> y = L.get(0);
370        GenWordPolynomial<C> t = y.multiply(S.val).sum(x);
371        if (!val.equals(t)) {
372            throw new NotDivisibleException("val != t: val = " + val + ", t = " + t);
373        }
374        return new WordResidue<C>(ring, y);
375    }
376
377
378    /**
379     * WordResidue two-sided division.
380     * @param S WordResidue.
381     * @return [left, right] with left*S*right + remainder = this.
382     */
383    @SuppressWarnings("unchecked")
384    public WordResidue<C>[] twosidedDivide(WordResidue<C> S) {
385        List<GenWordPolynomial<C>> L = new ArrayList<GenWordPolynomial<C>>(1);
386        L.add(ring.ring.getZERO());
387        List<GenWordPolynomial<C>> R = new ArrayList<GenWordPolynomial<C>>(1);
388        R.add(ring.ring.getZERO());
389        List<GenWordPolynomial<C>> V = new ArrayList<GenWordPolynomial<C>>(1);
390        V.add(S.val);
391        GenWordPolynomial<C> x = ring.bb.red.normalform(L, R, V, val);
392        GenWordPolynomial<C> y = L.get(0);
393        GenWordPolynomial<C> z = R.get(0);
394        if (!ring.bb.red.isReductionNF(L, R, V, val, x)) {
395            throw new NotDivisibleException("val != x: val = " + val + ", S.val = " + S.val);
396        }
397        WordResidue<C>[] ret = new WordResidue[2];
398        ret[0] = new WordResidue<C>(ring, y);
399        ret[1] = new WordResidue<C>(ring, z);
400        return ret;
401    }
402
403
404    /**
405     * WordResidue right division.
406     * @param S WordResidue.
407     * @return right, with S * right = this
408     */
409    public WordResidue<C> rightDivide(WordResidue<C> S) {
410        if (ring.isField()) {
411            return multiply(S.inverse());
412        }
413        try {
414            return multiply(S.inverse());
415        } catch (NotInvertibleException ignored) {
416            System.out.println("catch: " + ignored);
417            //ignored.printStackTrace();
418            // ignored
419        } catch (UnsupportedOperationException ignored) {
420            //System.out.println("catch: " + ignored);
421            //ignored.printStackTrace();
422            // ignored
423        }
424        List<GenWordPolynomial<C>> R = new ArrayList<GenWordPolynomial<C>>(1);
425        R.add(ring.ring.getZERO());
426        List<GenWordPolynomial<C>> V = new ArrayList<GenWordPolynomial<C>>(1);
427        V.add(S.val);
428        //@SuppressWarnings("unused")
429        GenWordPolynomial<C> x = ring.bb.red.rightNormalform(R, V, val);
430        GenWordPolynomial<C> y = R.get(0);
431        GenWordPolynomial<C> t = S.val.multiply(y).sum(x);
432        if (!val.equals(t)) {
433            throw new NotDivisibleException("val != t: val = " + val + ", t = " + t);
434        }
435        return new WordResidue<C>(ring, y);
436    }
437
438
439    /**
440     * WordResidue inverse.
441     * @see edu.jas.structure.RingElem#inverse()
442     * @return S with S = 1/this if defined.
443     */
444    public WordResidue<C> inverse() {
445        GenWordPolynomial<C> x = ring.ideal.inverse(val);
446        WordResidue<C> xp = new WordResidue<C>(ring, x, 1);
447        if (xp.isZERO()) {
448            throw new NotInvertibleException(
449                            "(" + x + ") * (" + val + ") = " + x.multiply(val) + " = 0 mod " + ring.ideal);
450        }
451        if (!xp.multiply(this).isONE()) {
452            throw new NotInvertibleException(
453                            "(" + x + ") * (" + val + ") = " + x.multiply(val) + " != 1 mod " + ring.ideal);
454        }
455        return xp;
456    }
457
458
459    /**
460     * WordResidue remainder.
461     * @param S WordResidue.
462     * @return this - (this/S) * S.
463     */
464    public WordResidue<C> remainder(WordResidue<C> S) {
465        List<GenWordPolynomial<C>> V = new ArrayList<GenWordPolynomial<C>>(1);
466        V.add(S.val);
467        GenWordPolynomial<C> x = ring.bb.red.leftNormalform(V, val);
468        return new WordResidue<C>(ring, x);
469    }
470
471
472    /**
473     * WordResidue right remainder.
474     * @param S WordResidue.
475     * @return r = this - S * (S/right), where S * right = this.
476     */
477    public WordResidue<C> rightRemainder(WordResidue<C> S) {
478        List<GenWordPolynomial<C>> V = new ArrayList<GenWordPolynomial<C>>(1);
479        V.add(S.val);
480        GenWordPolynomial<C> x = ring.bb.red.rightNormalform(V, val);
481        return new WordResidue<C>(ring, x);
482    }
483
484
485    /**
486     * WordResidue two-sided remainder.
487     * @param S WordResidue.
488     * @return r = this - left*S*right.
489     */
490    public WordResidue<C> twosidedRemainder(WordResidue<C> S) {
491        List<GenWordPolynomial<C>> V = new ArrayList<GenWordPolynomial<C>>(1);
492        V.add(S.val);
493        GenWordPolynomial<C> x = ring.bb.red.normalform(V, val);
494        WordResidue<C> ret = new WordResidue<C>(ring, x);
495        return ret;
496    }
497
498
499    /**
500     * WordResidue multiplication.
501     * @param S WordResidue.
502     * @return this*S.
503     */
504    public WordResidue<C> multiply(WordResidue<C> S) {
505        GenWordPolynomial<C> x = val.multiply(S.val);
506        int i = -1;
507        if (isunit == 1 && S.isunit == 1) {
508            i = 1;
509        } else if (isunit == 0 || S.isunit == 0) {
510            i = 0;
511        }
512        return new WordResidue<C>(ring, x, i);
513    }
514
515
516    /**
517     * WordResidue multiplication.
518     * @param S GenWordPolynomial.
519     * @return this*S.
520     */
521    public WordResidue<C> multiply(GenWordPolynomial<C> S) {
522        GenWordPolynomial<C> x = val.multiply(S);
523        int i = -1;
524        if (isunit == 1 && S.isUnit()) {
525            i = 1;
526        } else if (isunit == 0 || !S.isUnit()) {
527            i = 0;
528        }
529        return new WordResidue<C>(ring, x, i);
530    }
531
532
533    /*
534     * WordResidue multiplication.
535     * @param s coefficient.
536     * @return this*s.
537     */
538    public WordResidue<C> multiply(C s) {
539        GenWordPolynomial<C> x = val.multiply(s);
540        int i = -1;
541        if (isunit == 1 && s.isUnit()) {
542            i = 1;
543        } else if (isunit == 0 || !s.isUnit()) {
544            i = 0;
545        }
546        return new WordResidue<C>(ring, x, i);
547    }
548
549
550    /**
551     * WordResidue multiplication.
552     * @param e word.
553     * @return this*e.
554     */
555    public WordResidue<C> multiply(Word e) {
556        GenWordPolynomial<C> x = val.multiply(e);
557        int i = -1;
558        if (isunit == 1 && e.isONE()) {
559            i = 1;
560        } else if (isunit == 0 || !e.isONE()) {
561            i = 0;
562        }
563        return new WordResidue<C>(ring, x, i);
564    }
565
566
567    /**
568     * WordResidue monic.
569     * @return this with monic value part.
570     */
571    public WordResidue<C> monic() {
572        return new WordResidue<C>(ring, val.monic(), isunit);
573    }
574
575
576    /**
577     * Greatest common divisor.
578     * @param b other element.
579     * @return gcd(this,b).
580     */
581    public WordResidue<C> gcd(WordResidue<C> b) {
582        throw new UnsupportedOperationException("gcd not implemented");
583        // GenWordPolynomial<C> x = ring.engine.gcd(val, b.val);
584        // int i = -1; // gcd might become a unit
585        // if (x.isONE()) {
586        //     i = 1;
587        // } else {
588        //     System.out.println("WordResidue gcd = " + x);
589        // }
590        // if (isunit == 1 && b.isunit == 1) {
591        //     i = 1;
592        // }
593        // return new WordResidue<C>(ring, x, i);
594    }
595
596
597    /**
598     * Extended greatest common divisor. <b>Note: </b>Not implemented, throws
599     * UnsupportedOperationException.
600     * @param b other element.
601     * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b).
602     */
603    public WordResidue<C>[] egcd(WordResidue<C> b) {
604        throw new UnsupportedOperationException("egcd not implemented");
605    }
606}