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