package org.matheclipse.core.expression;

import org.apache.commons.math3.complex.Complex;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.form.output.OutputFormFactory;
import org.matheclipse.core.interfaces.IComplexNum;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.INum;
import org.matheclipse.core.interfaces.INumber;
import org.matheclipse.core.interfaces.ISignedNumber;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.core.visit.IVisitor;
import org.matheclipse.core.visit.IVisitorBoolean;
import org.matheclipse.core.visit.IVisitorInt;

/**
 * 
 */
public class ComplexNum extends ExprImpl implements IComplexNum {

	// private static final ObjectFactory FACTORY = new
	// ObjectFactory() {
	// @Override
	// protected ComplexNum create() {
	// if (Config.SERVER_MODE && currentQueue().getSize() >=
	// Config.DOUBLECOMPLEX_MAX_POOL_SIZE) {
	// throw new PoolMemoryExceededException("DoubleComplex",
	// currentQueue().getSize());
	// }
	// return new ComplexNum(0.0, 0.0);
	// }
	// };

	/**
	 * Be cautious with this method, no new internal couble complex is created
	 * 
	 * @param numerator
	 * @return
	 */
	protected static ComplexNum newInstance(final Complex value) {
		// ComplexNum d;
		// if (Config.SERVER_MODE) {
		// d = FACTORY.object();
		// } else {
		// d = new ComplexNum(0.0, 0.0);
		// }
		ComplexNum d = new ComplexNum(0.0, 0.0);
		d.fComplex = value;
		return d;
	}

	public static ComplexNum valueOf(final INum d) {
		return newInstance(new Complex(d.getRealPart(), 0.0));
	}

	public static ComplexNum valueOf(final double real) {
		return newInstance(new Complex(real, 0.0));
	}

	public static ComplexNum valueOf(final double real, final double imaginary) {
		return newInstance(new Complex(real, imaginary));
	}

	/**
	 * 
	 */
	private static final long serialVersionUID = -6033055105824482264L;

	/** The square root of -1. A number representing "0.0 + 1.0i" */
	public static final ComplexNum I = valueOf(0.0, 1.0);

	/** A complex number representing "NaN + NaNi" */
	public static final ComplexNum NaN = valueOf(Double.NaN, Double.NaN);

	/** A complex number representing "1.0 + 0.0i" */
	public static final ComplexNum ONE = valueOf(1.0, 0.0);

	/** A complex number representing "0.0 + 0.0i" */
	public static final ComplexNum ZERO = valueOf(0.0, 0.0);

	Complex fComplex;

	private ComplexNum(final double r, final double i) {
		fComplex = new Complex(r, i);
	}

	/**
	 * @return
	 */
	@Override
	public double getImaginaryPart() {
		double temp = fComplex.getImaginary();
		if (temp == (-0.0)) {
			temp = 0.0;
		}
		return temp;
	}

	/**
	 * @return
	 */
	@Override
	public double getRealPart() {
		double temp = fComplex.getReal();
		if (temp == (-0.0)) {
			temp = 0.0;
		}
		return temp;
	}

	@Override
	public boolean isZero() {
		return (fComplex.getReal() == 0.0) && (fComplex.getImaginary() == 0.0);
	}

	@Override
	public int hierarchy() {
		return DOUBLECOMPLEXID;
	}

	@Override
	public IComplexNum add(final IComplexNum val) {
		return newInstance(fComplex.add(((ComplexNum) val).fComplex));
	}

	public ComplexNum add(final ComplexNum that) {
		return newInstance(fComplex.add(that.fComplex));
	}

	@Override
	public IComplexNum multiply(final IComplexNum val) {
		return newInstance(fComplex.multiply(((ComplexNum) val).fComplex));
	}

	@Override
	public IComplexNum pow(final IComplexNum val) {
		return newInstance(fComplex.pow(((ComplexNum) val).fComplex));
	}

	/**
	 * @param that
	 * @return
	 */
	public Complex add(final Complex that) {
		return fComplex.add(that);
	}

	/**
	 * @return
	 */
	@Override
	public IComplexNum conjugate() {
		return newInstance(fComplex.conjugate());
	}

	/**
	 * @param that
	 * @return
	 */
	public Complex divide(final Complex that) {
		return fComplex.divide(that);
	}

	public ComplexNum divide(final ComplexNum that) throws ArithmeticException {
		return newInstance(fComplex.divide(that.fComplex));
	}

	/**
	 * @param k
	 * @return
	 */
	// public Complex divide(final double k) {
	// return fComplex.divide(k);
	// }
	/**
	 * @return
	 */
	// public double doubleValue() {
	// return fComplex.doubleValue();
	// }
	/**
	 * @param that
	 * @param tolerance
	 * @return
	 */
	// public boolean equals(final Complex that, final double tolerance) {
	// return fComplex.equals(that, tolerance);
	// }
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj instanceof ComplexNum) {
			return fComplex.equals(((ComplexNum) obj).fComplex);
		}
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public IExpr evaluate(EvalEngine engine) {
		if (F.isZero(getImaginaryPart())) {
			return F.num(getRealPart());
		}
		return null;
	}

	@Override
	public boolean isSame(IExpr expression, double epsilon) {
		if (expression instanceof ComplexNum) {
			return F.isZero(fComplex.getReal() - ((ComplexNum) expression).fComplex.getReal(), epsilon)
					&& F.isZero(fComplex.getImaginary() - ((ComplexNum) expression).fComplex.getImaginary(), epsilon);
			// return Math.abs(fComplex.getReal() - ((ComplexNum)
			// expression).fComplex.getReal()) < epsilon
			// && Math.abs(fComplex.getImaginary() - ((ComplexNum)
			// expression).fComplex.getImaginary()) < epsilon;
		}
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public double dabs() {
		if (isNaN()) {
			return Double.NaN;
		}

		if (isInfinite()) {
			return Double.POSITIVE_INFINITY;
		}

		if (Math.abs(getReal()) < Math.abs(getImaginary())) {
			if (getImaginary() == 0.0) {
				return Math.abs(getReal());
			}
			final double q = getReal() / getImaginary();
			return (Math.abs(getImaginary()) * Math.sqrt(1 + q * q));
		} else {
			if (getReal() == 0.0) {
				return Math.abs(getImaginary());
			}
			final double q = getImaginary() / getReal();
			return (Math.abs(getReal()) * Math.sqrt(1 + q * q));
		}
	}

	@Override
	public Num eabs() {
		return Num.valueOf(dabs());
	}

	/**
	 * @return
	 */
	// public Complex exp() {
	// return fComplex.exp();
	// }
	/**
	 * @return
	 */
	// public Object export() {
	// return fComplex.export();
	// }
	/**
	 * @return
	 */
	// public float floatValue() {
	// return fComplex.floatValue();
	// }
	/**
	 * @return
	 */
	public double getImaginary() {
		return fComplex.getImaginary();
	}

	/**
	 * @return
	 */
	public double getReal() {
		return fComplex.getReal();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public final int hashCode() {
		return fComplex.hashCode();
	}

	/**
	 * @return
	 */
	// public int intValue() {
	// return fComplex.intValue();
	// }
	/**
	 * @return
	 */
	public boolean isInfinite() {
		return fComplex.isInfinite();
	}

	/**
	 * @return
	 */
	public boolean isNaN() {
		return fComplex.isNaN();
	}

	/**
	 * @return
	 */
	// public Complex log() {
	// return fComplex.log();
	// }
	/**
	 * @return
	 */
	// public long longValue() {
	// return fComplex.longValue();
	// }
	/**
	 * @return
	 */
	// public double magnitude() {
	// return fComplex.magnitude();
	// }
	/**
	 * @param cs
	 */
	// @Override
	// public boolean move(final ObjectSpace cs) {
	// fComplex.move(cs);
	// return true;
	// }
	// public ComplexNum copy() {
	// // ComplexNum d;
	// // if (Config.SERVER_MODE) {
	// // d = FACTORY.object();
	// // } else {
	// // d = new ComplexNum(0.0, 0.0);
	// // }
	// ComplexNum d = new ComplexNum(0.0, 0.0);
	// d.fComplex = fComplex.copy();
	// return d;
	// }
	//
	// public ComplexNum copyNew() {
	// ComplexNum dci = new ComplexNum(0.0, 0.0);
	// dci.fComplex = new Complex(fComplex.getReal(), fComplex.getImaginary());
	// return dci;
	// }

	// public void recycle() {
	// FACTORY.recycle(this);
	// }

	/**
	 * @param that
	 * @return
	 */
	public ComplexNum multiply(final ComplexNum that) {
		return newInstance(fComplex.multiply(that.fComplex));
	}

	/**
	 * @return
	 */
	@Override
	public ComplexNum negate() {
		return newInstance(fComplex.negate());
	}

	/**
	 * @return
	 */
	@Override
	public INumber opposite() {
		return newInstance(fComplex.negate());
	}

	/**
	 * @param that
	 * @return
	 */
	@Override
	public IExpr plus(final IExpr that) {
		if (that instanceof ComplexNum) {
			return newInstance(fComplex.add(((ComplexNum) that).fComplex));
		}
		return super.plus(that);
	}

	/**
	 * @param that
	 * @return
	 */
	// public Complex pow(final Complex that) {
	// return fComplex.pow(that);
	// }
	/**
	 * @param e
	 * @return
	 */
	// public Complex pow(final double e) {
	// return fComplex.pow(e);
	// }
	/**
	 * @param exp
	 * @return
	 */
	// public Complex pow(final int exp) {
	// return fComplex.pow(exp);
	// }
	/**
	 * @param isPreserved
	 * @return
	 */
	// public Object preserve(boolean isPreserved) {
	// return fComplex.preserve(isPreserved);
	// }
	@Override
	public IExpr inverse() {
		// return new DoubleComplexImpl(fComplex.inverse());
		final double tmp = (fComplex.getReal() * fComplex.getReal()) + (fComplex.getImaginary() * fComplex.getImaginary());
		return valueOf(fComplex.getReal() / tmp, -fComplex.getImaginary() / tmp);
	}

	/**
	 * @return
	 */
	// public short shortValue() {
	// return fComplex.shortValue();
	// }
	/**
	 * @return
	 */
	// public Complex sqrt() {
	// return fComplex.sqrt();
	// }
	/**
	 * @param that
	 * @return
	 */
	public Complex subtract(final Complex that) {
		return fComplex.subtract(that);
	}

	public ComplexNum subtract(final ComplexNum that) {
		return newInstance(fComplex.subtract(that.fComplex));
	}

	/**
	 * @param that
	 * @return
	 */
	@Override
	public IExpr times(final IExpr that) {
		if (that instanceof ComplexNum) {
			return newInstance(fComplex.multiply(((ComplexNum) that).fComplex));
		}
		return super.times(that);
	}

	@Override
	public String toString() {
		try {
			StringBuilder sb = new StringBuilder();
			OutputFormFactory.get().convertDoubleComplex(sb, this, Integer.MIN_VALUE);
			return sb.toString();
		} catch (Exception e1) {
		}
		// fall back to simple output format
		return fComplex.toString();
	}

	/**
	 * @return
	 */
	// @Override
	// public Text toText() {
	// return fComplex.toText();
	// }
	@Override
	public int complexSign() {
		final int i = (int) Math.signum(fComplex.getReal());
		if (i == 0) {
			return (int) Math.signum(fComplex.getImaginary());
		}
		return i;
	}

	public int compareTo(final Complex that) {
		if (fComplex.getReal() < that.getReal()) {
			return -1;
		}
		if (fComplex.getReal() > that.getReal()) {
			return 1;
		}
		long l1 = Double.doubleToLongBits(fComplex.getReal());
		long l2 = Double.doubleToLongBits(that.getReal());
		if (l1 < l2) {
			return -1;
		}
		if (l2 > l1) {
			return 1;
		}
		if (fComplex.getImaginary() < that.getImaginary()) {
			return -1;
		}
		if (fComplex.getImaginary() > that.getImaginary()) {
			return 1;
		}
		l1 = Double.doubleToLongBits(fComplex.getImaginary());
		l2 = Double.doubleToLongBits(that.getImaginary());
		if (l1 < l2) {
			return -1;
		}
		if (l2 > l1) {
			return 1;
		}
		return 0;
	}

	/**
	 * Compares this expression with the specified expression for order. Returns a negative integer, zero, or a positive integer as
	 * this expression is canonical less than, equal to, or greater than the specified expression.
	 */
	@Override
	public int compareTo(final IExpr obj) {
		if (obj instanceof ComplexNum) {
			return compareTo(((ComplexNum) obj).fComplex);
			// return fComplex.compareTo(((DoubleComplexImpl) obj).fComplex);
		}
		return (hierarchy() - (obj).hierarchy());
	}

	@Override
	public ISymbol head() {
		return F.Complex;
	}

	public Complex getComplex() {
		return fComplex;
	}

	public org.matheclipse.parser.client.math.Complex getCMComplex() {
		return new org.matheclipse.parser.client.math.Complex(fComplex.getReal(), fComplex.getImaginary());
	}

	/** {@inheritDoc} */
	@Override
	public  T accept(IVisitor visitor) {
		return visitor.visit(this);
	}

	/** {@inheritDoc} */
	@Override
	public boolean accept(IVisitorBoolean visitor) {
		return visitor.visit(this);
	}

	/** {@inheritDoc} */
	@Override
	public int accept(IVisitorInt visitor) {
		return visitor.visit(this);
	}

	@Override
	public boolean equalsInt(int i) {
		return false;
	}

	/** {@inheritDoc} */
	@Override
	public ISignedNumber getIm() { 
		return F.num(getImaginaryPart());
	}

	/** {@inheritDoc} */
	@Override
	public ISignedNumber getRe() {
		return F.num(getRealPart());
	}
}
 

Ads help maintain this website.