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 }