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 }