001    /*
002     * $Id: Local.java 3358 2010-10-23 19:27:53Z kredel $
003     */
004    
005    package edu.jas.application;
006    
007    import java.util.ArrayList;
008    import java.util.List;
009    
010    import org.apache.log4j.Logger;
011    
012    import edu.jas.poly.GenPolynomial;
013    
014    import edu.jas.kern.PrettyPrint;
015    
016    import edu.jas.structure.RingElem;
017    import edu.jas.structure.RingFactory;
018    import edu.jas.structure.GcdRingElem;
019    
020    
021    /**
022     * Local ring element based on GenPolynomial with RingElem interface.
023     * Objects of this class are (nearly) immutable.
024     * @author Heinz Kredel
025     * @fix Not jet working because of monic GBs.
026     */
027    public class Local<C extends GcdRingElem<C> > 
028                 implements RingElem< Local<C> > {
029    
030    
031      private static final Logger logger = Logger.getLogger(Local.class);
032      private boolean debug = logger.isDebugEnabled();
033    
034    
035        /** Local class factory data structure. 
036         */
037        public final LocalRing<C> ring;
038    
039    
040        /** Numerator part of the element data structure. 
041         */
042        protected final GenPolynomial<C> num;
043    
044    
045        /** Denominator part of the element data structure. 
046         */
047        protected final GenPolynomial<C> den;
048    
049    
050        /** Flag to remember if this local element is a unit.
051         * -1 is unknown, 1 is unit, 0 not a unit.
052         */
053        protected int isunit = -1; // initially unknown
054    
055    
056    
057        /** The constructor creates a Local object 
058         * from a ring factory. 
059         * @param r ring factory.
060         */
061        public Local(LocalRing<C> r) {
062            this( r, r.ring.getZERO() );
063        }
064    
065    
066        /** The constructor creates a Local object 
067         * from a ring factory and a numerator polynomial. 
068         * The denominator is assumed to be 1.
069         * @param r ring factory.
070         * @param n numerator polynomial.
071         */
072        public Local(LocalRing<C> r, GenPolynomial<C> n) {
073            this( r, n, r.ring.getONE(), true );
074        }
075    
076    
077        /** The constructor creates a Local object 
078         * from a ring factory and a numerator and denominator polynomial. 
079         * @param r ring factory.
080         * @param n numerator polynomial.
081         * @param d denominator polynomial.
082         */
083        public Local(LocalRing<C> r, 
084                     GenPolynomial<C> n, GenPolynomial<C> d) {
085            this(r,n,d,false);
086        }
087    
088    
089        /** The constructor creates a Local object 
090         * from a ring factory and a numerator and denominator polynomial. 
091         * @param r ring factory.
092         * @param n numerator polynomial.
093         * @param d denominator polynomial.
094         * @param isred true if gcd(n,d) == 1, else false.
095         */
096        protected Local(LocalRing<C> r, 
097                        GenPolynomial<C> n, GenPolynomial<C> d,
098                        boolean isred) {
099            if ( d == null || d.isZERO() ) {
100               throw new IllegalArgumentException("denominator may not be zero");
101            }
102            ring = r;
103            if ( d.signum() < 0 ) {
104               n = n.negate();
105               d = d.negate();
106            }
107            if ( isred ) {
108               num = n;
109               den = d;
110               return;
111            }
112            GenPolynomial<C> p = ring.ideal.normalform( d );
113            if ( p == null || p.isZERO() ) {
114               throw new IllegalArgumentException("denominator may not be in ideal");
115            }
116            //d = p; cant do this
117            // must reduce to lowest terms
118            //GenPolynomial<C> gcd = ring.ring.getONE();
119            GenPolynomial<C> gcd = gcd( n, d );
120            if ( true || debug ) {
121               logger.info("gcd = " + gcd);
122            }
123            if ( gcd.isONE() ) {
124               num = n;
125               den = d;
126            } else {
127               // d not in ideal --> gcd not in ideal 
128               //p = ring.ideal.normalform( gcd );
129               //if ( p == null || p.isZERO() ) { // todo: find nonzero factor
130               //   num = n;
131               //   den = d;
132               //} else {
133                  num = n.divide( gcd );
134                  den = d.divide( gcd );
135               //}
136            }
137        }
138    
139    
140        /** Least common multiple.
141         * @param n first polynomial.
142         * @param d second polynomial.
143         * @return lcm(n,d)
144         */
145        protected GenPolynomial<C> lcm(GenPolynomial<C> n, GenPolynomial<C> d) {
146            GenPolynomial<C> lcm = ring.engine.lcm(n,d);
147            return lcm;
148        }
149    
150    
151        /** Greatest common divisor.
152         * Just for fun, is not efficient.
153         * @param n first polynomial.
154         * @param d second polynomial.
155         * @return gcd(n,d)
156         */
157        protected GenPolynomial<C> gcd(GenPolynomial<C> n, GenPolynomial<C> d) {
158            if ( n.isZERO() ) {
159               return d;
160            }
161            if ( d.isZERO() ) {
162               return n;
163            }
164            if ( n.isONE() ) {
165               return n;
166            }
167            if ( d.isONE() ) {
168               return d;
169            }
170            GenPolynomial<C> gcd = ring.engine.gcd(n,d);
171            return gcd;
172        }
173    
174    
175        /**
176         * Get the corresponding element factory.
177         * @return factory for this Element.
178         * @see edu.jas.structure.Element#factory()
179         */
180        public LocalRing<C> factory() {
181            return ring;
182        }
183    
184    
185        /**  Clone this.
186         * @see java.lang.Object#clone()
187         */
188        @Override
189         public Local<C> clone() {
190            return new Local<C>( ring, num, den, true );
191        }
192       
193    
194        /** Is Local zero. 
195         * @return If this is 0 then true is returned, else false.
196         * @see edu.jas.structure.RingElem#isZERO()
197         */
198        public boolean isZERO() {
199            return num.isZERO();
200        }
201    
202    
203        /** Is Local one. 
204         * @return If this is 1 then true is returned, else false.
205         * @see edu.jas.structure.RingElem#isONE()
206         */
207        public boolean isONE() {
208            return num.equals( den );
209        }
210    
211    
212        /** Is Local unit. 
213         * @return If this is a unit then true is returned, else false.
214         * @see edu.jas.structure.RingElem#isUnit()
215         */
216        public boolean isUnit() {
217            if ( isunit > 0 ) {
218                return true;
219            } 
220            if ( isunit == 0 ) {
221                return false;
222            } 
223            // not jet known
224            if ( num.isZERO() ) {
225               isunit = 0;
226               return false;
227            }
228            GenPolynomial<C> p = ring.ideal.normalform( num );
229            boolean u = ( p != null && ! p.isZERO() );
230            if ( u ) {
231               isunit = 1;
232            } else {
233               isunit = 0;
234            }
235            return ( u );
236        }
237    
238    
239        /** Get the String representation as RingElem.
240         * @see java.lang.Object#toString()
241         */
242        @Override
243         public String toString() {
244            if ( PrettyPrint.isTrue() ) {
245                String s = "{ " + num.toString( ring.ring.getVars() );
246                if ( den.isONE() ) {
247                    return s + " }";
248                }
249                return s + "| " + den.toString( ring.ring.getVars() ) + " }";
250            } else {
251               return "Local[ " + num.toString() 
252                        + " | " + den.toString() + " ]";
253            }
254        }
255    
256    
257        /** Get a scripting compatible string representation.
258         * @return script compatible representation for this Element.
259         * @see edu.jas.structure.Element#toScript()
260         */
261        //JAVA6only: @Override
262        public String toScript() {
263            // Python case
264            if ( den.isONE() ) {
265                return num.toScript();
266            } else {
267                return num.toScript() + " / " + den.toScript();
268            }
269        }
270    
271    
272        /** Get a scripting compatible string representation of the factory.
273         * @return script compatible representation for this ElemFactory.
274         * @see edu.jas.structure.Element#toScriptFactory()
275         */
276        //JAVA6only: @Override
277        public String toScriptFactory() {
278            // Python case
279            return factory().toScript();
280        }
281    
282    
283        /** Local comparison.  
284         * @param b Local.
285         * @return sign(this-b).
286         */
287        //JAVA6only: @Override
288        public int compareTo(Local<C> b) {
289            if ( b == null || b.isZERO() ) {
290                return this.signum();
291            }
292            GenPolynomial<C> r = num.multiply( b.den );
293            GenPolynomial<C> s = den.multiply( b.num );
294            GenPolynomial<C> x = r.subtract( s );
295            return x.signum();
296        }
297    
298    
299        /** Comparison with any other object.
300         * @see java.lang.Object#equals(java.lang.Object)
301         */
302        @SuppressWarnings("unchecked") // not jet working
303        @Override
304        public boolean equals(Object b) {
305            if ( ! ( b instanceof Local ) ) {
306               return false;
307            }
308            Local<C> a = null;
309            try {
310                a = (Local<C>) b;
311            } catch (ClassCastException e) {
312            }
313            if ( a == null ) {
314                return false;
315            }
316            return ( 0 == compareTo( a ) );
317        }
318    
319    
320        /** Hash code for this local.
321         * @see java.lang.Object#hashCode()
322         */
323        @Override
324        public int hashCode() { 
325           int h;
326           h = ring.hashCode();
327           h = 37 * h + num.hashCode();
328           h = 37 * h + den.hashCode();
329           return h;
330        }
331    
332    
333        /** Local absolute value.
334         * @return the absolute value of this.
335         * @see edu.jas.structure.RingElem#abs()
336         */
337        public Local<C> abs() {
338            return new Local<C>( ring, num.abs(), den, true );
339        }
340    
341    
342        /** Local summation.
343         * @param S Local.
344         * @return this+S.
345         */
346        public Local<C> sum(Local<C> S) {
347            if ( S == null || S.isZERO() ) {
348               return this;
349            }
350            GenPolynomial<C> n = num.multiply( S.den );
351            n = n.sum( den.multiply( S.num ) ); 
352            GenPolynomial<C> d = den.multiply( S.den );
353            return new Local<C>( ring, n, d, false );
354        }
355    
356    
357        /** Local negate.
358         * @return -this.
359         * @see edu.jas.structure.RingElem#negate()
360         */
361        public Local<C> negate() {
362            return new Local<C>( ring, num.negate(), den, true );
363        }
364    
365    
366        /** Local signum.
367         * @see edu.jas.structure.RingElem#signum()
368         * @return signum(this).
369         */
370        public int signum() {
371            return num.signum();
372        }
373    
374    
375        /** Local subtraction.
376         * @param S Local.
377         * @return this-S.
378         */
379        public Local<C> subtract(Local<C> S) {
380            if ( S == null || S.isZERO() ) {
381               return this;
382            }
383            GenPolynomial<C> n = num.multiply( S.den );
384            n = n.subtract( den.multiply( S.num ) ); 
385            GenPolynomial<C> d = den.multiply( S.den );
386            return new Local<C>( ring, n, d, false );
387        }
388    
389    
390        /** Local division.
391         * @param S Local.
392         * @return this/S.
393         */
394        public Local<C> divide(Local<C> S) {
395            return multiply( S.inverse() );
396        }
397    
398    
399        /** Local inverse.  
400         * @see edu.jas.structure.RingElem#inverse()
401         * @return S with S = 1/this if defined. 
402         */
403        public Local<C> inverse() {
404            if ( isONE() ) {
405               return this;
406            }
407            if ( isUnit() ) {
408               return new Local<C>( ring, den, num, true );
409            }
410            throw new ArithmeticException("element not invertible " + this);
411        }
412    
413    
414        /** Local remainder.
415         * @param S Local.
416         * @return this - (this/S)*S.
417         */
418        public Local<C> remainder(Local<C> S) {
419            if ( num.isZERO() ) {
420               throw new ArithmeticException("element not invertible " + this);
421            }
422            if ( S.isUnit() ) {
423               return ring.getZERO(); 
424            } else {
425               throw new UnsupportedOperationException("remainder not implemented" + S);
426            }
427        }
428    
429    
430        /** Local multiplication.
431         * @param S Local.
432         * @return this*S.
433         */
434        public Local<C> multiply(Local<C> S) {
435            if ( S == null || S.isZERO() ) {
436               return S;
437            }
438            if ( num.isZERO() ) {
439               return this;
440            }
441            if ( S.isONE() ) {
442               return this;
443            }
444            if ( this.isONE() ) {
445               return S;
446            }
447            GenPolynomial<C> n = num.multiply( S.num );
448            GenPolynomial<C> d = den.multiply( S.den );
449            return new Local<C>( ring, n, d, false );
450        }
451    
452     
453        /** Local monic.
454         * @return this with monic value part.
455         */
456        public Local<C> monic() {
457            if ( num.isZERO() ) {
458               return this;
459            }
460            C lbc = num.leadingBaseCoefficient();
461            lbc = lbc.inverse();
462            GenPolynomial<C> n = num.multiply( lbc );
463            GenPolynomial<C> d = den.multiply( lbc );
464            return new Local<C>( ring, n, d, true );
465        }
466    
467    
468        /**
469         * Greatest common divisor.
470         * @param b other element.
471         * @return gcd(this,b).
472         */
473        public Local<C> gcd(Local<C> b) {
474            GenPolynomial<C> x = ring.engine.gcd( num, b.num );
475            GenPolynomial<C> y = ring.engine.gcd( den, b.den );
476            return new Local<C>( ring, x, y, true );
477            // throw new UnsupportedOperationException("gcd not implemented " + this.getClass().getName());
478        }
479    
480    
481        /**
482         * Extended greatest common divisor.
483         * <b>Note: </b>Not implemented, throws UnsupportedOperationException.
484         * @param b other element.
485         * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b).
486         */
487        public Local<C>[] egcd(Local<C> b) {
488            throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName());
489        }
490    
491    }