/*
* $Id: Local.java 3358 2010-10-23 19:27:53Z kredel $
*/
package edu.jas.application;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import edu.jas.poly.GenPolynomial;
import edu.jas.kern.PrettyPrint;
import edu.jas.structure.RingElem;
import edu.jas.structure.RingFactory;
import edu.jas.structure.GcdRingElem;
/**
* Local ring element based on GenPolynomial with RingElem interface.
* Objects of this class are (nearly) immutable.
* @author Heinz Kredel
* @fix Not jet working because of monic GBs.
*/
public class Local<C extends GcdRingElem<C> >
implements RingElem< Local<C> > {
private static final Logger logger = Logger.getLogger(Local.class);
private boolean debug = logger.isDebugEnabled();
/** Local class factory data structure.
*/
public final LocalRing<C> ring;
/** Numerator part of the element data structure.
*/
protected final GenPolynomial<C> num;
/** Denominator part of the element data structure.
*/
protected final GenPolynomial<C> den;
/** Flag to remember if this local element is a unit.
* -1 is unknown, 1 is unit, 0 not a unit.
*/
protected int isunit = -1; // initially unknown
/** The constructor creates a Local object
* from a ring factory.
* @param r ring factory.
*/
public Local(LocalRing<C> r) {
this( r, r.ring.getZERO() );
}
/** The constructor creates a Local object
* from a ring factory and a numerator polynomial.
* The denominator is assumed to be 1.
* @param r ring factory.
* @param n numerator polynomial.
*/
public Local(LocalRing<C> r, GenPolynomial<C> n) {
this( r, n, r.ring.getONE(), true );
}
/** The constructor creates a Local object
* from a ring factory and a numerator and denominator polynomial.
* @param r ring factory.
* @param n numerator polynomial.
* @param d denominator polynomial.
*/
public Local(LocalRing<C> r,
GenPolynomial<C> n, GenPolynomial<C> d) {
this(r,n,d,false);
}
/** The constructor creates a Local object
* from a ring factory and a numerator and denominator polynomial.
* @param r ring factory.
* @param n numerator polynomial.
* @param d denominator polynomial.
* @param isred true if gcd(n,d) == 1, else false.
*/
protected Local(LocalRing<C> r,
GenPolynomial<C> n, GenPolynomial<C> d,
boolean isred) {
if ( d == null || d.isZERO() ) {
throw new IllegalArgumentException("denominator may not be zero");
}
ring = r;
if ( d.signum() < 0 ) {
n = n.negate();
d = d.negate();
}
if ( isred ) {
num = n;
den = d;
return;
}
GenPolynomial<C> p = ring.ideal.normalform( d );
if ( p == null || p.isZERO() ) {
throw new IllegalArgumentException("denominator may not be in ideal");
}
//d = p; cant do this
// must reduce to lowest terms
//GenPolynomial<C> gcd = ring.ring.getONE();
GenPolynomial<C> gcd = gcd( n, d );
if ( true || debug ) {
logger.info("gcd = " + gcd);
}
if ( gcd.isONE() ) {
num = n;
den = d;
} else {
// d not in ideal --> gcd not in ideal
//p = ring.ideal.normalform( gcd );
//if ( p == null || p.isZERO() ) { // todo: find nonzero factor
// num = n;
// den = d;
//} else {
num = n.divide( gcd );
den = d.divide( gcd );
//}
}
}
/** Least common multiple.
* @param n first polynomial.
* @param d second polynomial.
* @return lcm(n,d)
*/
protected GenPolynomial<C> lcm(GenPolynomial<C> n, GenPolynomial<C> d) {
GenPolynomial<C> lcm = ring.engine.lcm(n,d);
return lcm;
}
/** Greatest common divisor.
* Just for fun, is not efficient.
* @param n first polynomial.
* @param d second polynomial.
* @return gcd(n,d)
*/
protected GenPolynomial<C> gcd(GenPolynomial<C> n, GenPolynomial<C> d) {
if ( n.isZERO() ) {
return d;
}
if ( d.isZERO() ) {
return n;
}
if ( n.isONE() ) {
return n;
}
if ( d.isONE() ) {
return d;
}
GenPolynomial<C> gcd = ring.engine.gcd(n,d);
return gcd;
}
/**
* Get the corresponding element factory.
* @return factory for this Element.
* @see edu.jas.structure.Element#factory()
*/
public LocalRing<C> factory() {
return ring;
}
/** Clone this.
* @see java.lang.Object#clone()
*/
@Override
public Local<C> clone() {
return new Local<C>( ring, num, den, true );
}
/** Is Local zero.
* @return If this is 0 then true is returned, else false.
* @see edu.jas.structure.RingElem#isZERO()
*/
public boolean isZERO() {
return num.isZERO();
}
/** Is Local one.
* @return If this is 1 then true is returned, else false.
* @see edu.jas.structure.RingElem#isONE()
*/
public boolean isONE() {
return num.equals( den );
}
/** Is Local unit.
* @return If this is a unit then true is returned, else false.
* @see edu.jas.structure.RingElem#isUnit()
*/
public boolean isUnit() {
if ( isunit > 0 ) {
return true;
}
if ( isunit == 0 ) {
return false;
}
// not jet known
if ( num.isZERO() ) {
isunit = 0;
return false;
}
GenPolynomial<C> p = ring.ideal.normalform( num );
boolean u = ( p != null && ! p.isZERO() );
if ( u ) {
isunit = 1;
} else {
isunit = 0;
}
return ( u );
}
/** Get the String representation as RingElem.
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
if ( PrettyPrint.isTrue() ) {
String s = "{ " + num.toString( ring.ring.getVars() );
if ( den.isONE() ) {
return s + " }";
}
return s + "| " + den.toString( ring.ring.getVars() ) + " }";
} else {
return "Local[ " + num.toString()
+ " | " + den.toString() + " ]";
}
}
/** Get a scripting compatible string representation.
* @return script compatible representation for this Element.
* @see edu.jas.structure.Element#toScript()
*/
//JAVA6only: @Override
public String toScript() {
// Python case
if ( den.isONE() ) {
return num.toScript();
} else {
return num.toScript() + " / " + den.toScript();
}
}
/** Get a scripting compatible string representation of the factory.
* @return script compatible representation for this ElemFactory.
* @see edu.jas.structure.Element#toScriptFactory()
*/
//JAVA6only: @Override
public String toScriptFactory() {
// Python case
return factory().toScript();
}
/** Local comparison.
* @param b Local.
* @return sign(this-b).
*/
//JAVA6only: @Override
public int compareTo(Local<C> b) {
if ( b == null || b.isZERO() ) {
return this.signum();
}
GenPolynomial<C> r = num.multiply( b.den );
GenPolynomial<C> s = den.multiply( b.num );
GenPolynomial<C> x = r.subtract( s );
return x.signum();
}
/** Comparison with any other object.
* @see java.lang.Object#equals(java.lang.Object)
*/
@SuppressWarnings("unchecked") // not jet working
@Override
public boolean equals(Object b) {
if ( ! ( b instanceof Local ) ) {
return false;
}
Local<C> a = null;
try {
a = (Local<C>) b;
} catch (ClassCastException e) {
}
if ( a == null ) {
return false;
}
return ( 0 == compareTo( a ) );
}
/** Hash code for this local.
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int h;
h = ring.hashCode();
h = 37 * h + num.hashCode();
h = 37 * h + den.hashCode();
return h;
}
/** Local absolute value.
* @return the absolute value of this.
* @see edu.jas.structure.RingElem#abs()
*/
public Local<C> abs() {
return new Local<C>( ring, num.abs(), den, true );
}
/** Local summation.
* @param S Local.
* @return this+S.
*/
public Local<C> sum(Local<C> S) {
if ( S == null || S.isZERO() ) {
return this;
}
GenPolynomial<C> n = num.multiply( S.den );
n = n.sum( den.multiply( S.num ) );
GenPolynomial<C> d = den.multiply( S.den );
return new Local<C>( ring, n, d, false );
}
/** Local negate.
* @return -this.
* @see edu.jas.structure.RingElem#negate()
*/
public Local<C> negate() {
return new Local<C>( ring, num.negate(), den, true );
}
/** Local signum.
* @see edu.jas.structure.RingElem#signum()
* @return signum(this).
*/
public int signum() {
return num.signum();
}
/** Local subtraction.
* @param S Local.
* @return this-S.
*/
public Local<C> subtract(Local<C> S) {
if ( S == null || S.isZERO() ) {
return this;
}
GenPolynomial<C> n = num.multiply( S.den );
n = n.subtract( den.multiply( S.num ) );
GenPolynomial<C> d = den.multiply( S.den );
return new Local<C>( ring, n, d, false );
}
/** Local division.
* @param S Local.
* @return this/S.
*/
public Local<C> divide(Local<C> S) {
return multiply( S.inverse() );
}
/** Local inverse.
* @see edu.jas.structure.RingElem#inverse()
* @return S with S = 1/this if defined.
*/
public Local<C> inverse() {
if ( isONE() ) {
return this;
}
if ( isUnit() ) {
return new Local<C>( ring, den, num, true );
}
throw new ArithmeticException("element not invertible " + this);
}
/** Local remainder.
* @param S Local.
* @return this - (this/S)*S.
*/
public Local<C> remainder(Local<C> S) {
if ( num.isZERO() ) {
throw new ArithmeticException("element not invertible " + this);
}
if ( S.isUnit() ) {
return ring.getZERO();
} else {
throw new UnsupportedOperationException("remainder not implemented" + S);
}
}
/** Local multiplication.
* @param S Local.
* @return this*S.
*/
public Local<C> multiply(Local<C> S) {
if ( S == null || S.isZERO() ) {
return S;
}
if ( num.isZERO() ) {
return this;
}
if ( S.isONE() ) {
return this;
}
if ( this.isONE() ) {
return S;
}
GenPolynomial<C> n = num.multiply( S.num );
GenPolynomial<C> d = den.multiply( S.den );
return new Local<C>( ring, n, d, false );
}
/** Local monic.
* @return this with monic value part.
*/
public Local<C> monic() {
if ( num.isZERO() ) {
return this;
}
C lbc = num.leadingBaseCoefficient();
lbc = lbc.inverse();
GenPolynomial<C> n = num.multiply( lbc );
GenPolynomial<C> d = den.multiply( lbc );
return new Local<C>( ring, n, d, true );
}
/**
* Greatest common divisor.
* @param b other element.
* @return gcd(this,b).
*/
public Local<C> gcd(Local<C> b) {
GenPolynomial<C> x = ring.engine.gcd( num, b.num );
GenPolynomial<C> y = ring.engine.gcd( den, b.den );
return new Local<C>( ring, x, y, true );
// throw new UnsupportedOperationException("gcd not implemented " + this.getClass().getName());
}
/**
* Extended greatest common divisor.
* <b>Note: </b>Not implemented, throws UnsupportedOperationException.
* @param b other element.
* @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b).
*/
public Local<C>[] egcd(Local<C> b) {
throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName());
}
}
|