syncleus.dann.math.ComplexNumber.java Source code

Java tutorial

Introduction

Here is the source code for syncleus.dann.math.ComplexNumber.java

Source

/******************************************************************************
 *                                                                             *
 *  Copyright: (c) Syncleus, Inc.                                              *
 *                                                                             *
 *  You may redistribute and modify this source code under the terms and       *
 *  conditions of the Open Source Community License - Type C version 1.0       *
 *  or any later version as published by Syncleus, Inc. at www.syncleus.com.   *
 *  There should be a copy of the license included with this file. If a copy   *
 *  of the license is not included you are granted no right to distribute or   *
 *  otherwise use this file except through a legal and valid license. You      *
 *  should also contact Syncleus, Inc. at the information below if you cannot  *
 *  find a license:                                                            *
 *                                                                             *
 *  Syncleus, Inc.                                                             *
 *  2604 South 12th Street                                                     *
 *  Philadelphia, PA 19148                                                     *
 *                                                                             *
 ******************************************************************************/

/*
 * Derived from the Public-Domain sources found at
 * http://www.cs.princeton.edu/introcs/97data/ as of 9/13/2009.
 */
package syncleus.dann.math;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import syncleus.dann.math.geometry.TrigonometricAlgebraic;

//TODO subclass http://commons.apache.org/proper/commons-math/javadocs/api-3.3/org/apache/commons/math3/complex/Complex.html

public class ComplexNumber extends org.apache.commons.math3.complex.Complex
        implements TrigonometricAlgebraic<ComplexNumber> {

    public static final class Field implements syncleus.dann.math.OrderedField<ComplexNumber> {
        public static final Field FIELD = new Field();

        public static ComplexNumber getImaginaryUnit() {
            return ComplexNumber.I;
        }

        private Field() {
        }

        @Override
        public ComplexNumber getOne() {
            return ComplexNumber.ONE;
        }

        @Override
        public ComplexNumber getZero() {
            return ComplexNumber.ZERO;
        }
    }

    public static final ComplexNumber I = new ComplexNumber(0, 1);
    public static final ComplexNumber ONE = new ComplexNumber(1, 0);
    public static final ComplexNumber ZERO = new ComplexNumber(0, 0);

    public static ComplexNumber multiply(final ComplexNumber... values) {
        ComplexNumber complexProduct = new ComplexNumber(1.0, 0.0);
        for (final ComplexNumber value : values)
            complexProduct = complexProduct.multiply(value);
        return complexProduct;
    }

    public static ComplexNumber polarToComplex(final double radius, final double theta) {
        if (radius < 0)
            throw new IllegalArgumentException("r must be greater than or equal to 0");
        return new ComplexNumber(Math.cos(theta) * radius, Math.sin(theta) * radius);
    }

    public static ComplexNumber scalarToComplex(final double scalar) {
        return new ComplexNumber(scalar, 0.0);
    }

    public static ComplexNumber scalarToComplex(final float scalar) {
        return new ComplexNumber(scalar, 0.0);
    }

    public static ComplexNumber scalarToComplex(final int scalar) {
        return new ComplexNumber(scalar, 0.0);
    }

    public static ComplexNumber scalarToComplex(final long scalar) {
        return new ComplexNumber(scalar, 0.0);
    }

    public static ComplexNumber scalarToComplex(final short scalar) {
        return new ComplexNumber(scalar, 0.0);
    }

    public static ComplexNumber sum(final ComplexNumber... values) {
        ComplexNumber complexSum = ComplexNumber.ZERO;
        for (final ComplexNumber value : values)
            complexSum = complexSum.add(value);
        return complexSum;
    }

    public ComplexNumber(final double imaginary) {
        super(0, imaginary);
    }

    public ComplexNumber(ComplexNumber c) {
        this(c.getReal(), c.getImaginary());
    }

    public ComplexNumber(final double real, final double imaginary) {
        super(real, imaginary);
    }

    public final double absScalar() {
        return Math.hypot(this.getReal(), this.getImaginary());
    }

    @Override
    public final ComplexNumber acos() {
        return this.add(this.sqrt1Minus().multiply(ComplexNumber.I)).log().multiply(ComplexNumber.I.negate());
    }

    @Override
    public final ComplexNumber add(final org.apache.commons.math3.complex.Complex value) {
        return new ComplexNumber(getReal() + value.getReal(), getImaginary() + value.getImaginary());
    }

    @Override
    public ComplexNumber add(ComplexNumber value) {
        return new ComplexNumber(getReal() + value.getReal(), getImaginary() + value.getImaginary());
    }

    @Override
    public ComplexNumber algebraicAbsolute() {
        return new ComplexNumber(this.absScalar(), 0.0);
    }

    @Override
    public final ComplexNumber add(final double value) {
        return this.add(new ComplexNumber(value, 0.0));
    }

    /**
     * Argument of this Complex number (the angle in radians with the x-axis in
     * polar coordinates).
     *
     * @return arg(z) where z is this Complex number.
     */
    public double arg() {
        return Math.atan2(getImaginary(), getReal());
    }

    @Override
    public final ComplexNumber asin() {
        return sqrt1Minus().add(this.multiply(ComplexNumber.I)).log().multiply(ComplexNumber.I.negate());
    }

    @Override
    public final ComplexNumber atan() {
        return this.add(ComplexNumber.I).divide(ComplexNumber.I.subtract(this)).log()
                .multiply(ComplexNumber.I.divide(new ComplexNumber(2.0, 0.0)));
    }

    /**
     * Negative of this complex number (chs stands for change sign). This
     * produces a new Complex number and doesn't change this Complex number. <br>
     * -(x+i*y) = -x-i*y.
     *
     * @return -z where z is this Complex number.
     */
    public ComplexNumber chs() {
        return new ComplexNumber(-getReal(), -getImaginary());
    }

    /**
     * Complex conjugate of this Complex number (the conjugate of x+i*y is
     * x-i*y).
     *
     * @return z-bar where z is this Complex number.
     */
    public ComplexNumber conj() {
        return new ComplexNumber(getReal(), -getImaginary());
    }

    @Override
    public final ComplexNumber conjugate() {
        return new ComplexNumber(getReal(), -getImaginary());
    }

    /**
     * Cosine of this Complex number (doesn't change this Complex number). <br>
     * cos(z) = (exp(i*z)+exp(-i*z))/ 2.
     *
     * @return cos(z) where z is this Complex number.
     */
    @Override
    public ComplexNumber cos() {
        return new ComplexNumber(cosh(getImaginary()) * Math.cos(getReal()),
                -sinh(getImaginary()) * Math.sin(getReal()));
    }

    /**
     * Hyperbolic cosine of this Complex number (doesn't change this Complex
     * number). <br>
     * cosh(z) = (exp(z) + exp(-z)) / 2.
     *
     * @return cosh(z) where z is this Complex number.
     */
    @Override
    public ComplexNumber cosh() {
        return new ComplexNumber(cosh(getReal()) * Math.cos(getImaginary()),
                sinh(getReal()) * Math.sin(getImaginary()));
    }

    // Real cosh function (used to compute complex trig functions)
    private static double cosh(final double theta) {
        return (Math.exp(theta) + Math.exp(-theta)) / 2;
    }

    /**
     * Division of Complex numbers (doesn't change this Complex number). <br>
     * (x+i*y)/(s+i*t) = ((x*s+y*t) + i*(y*s-y*t)) / (s^2+t^2)
     *
     * @param w is the number to divide by
     * @return new Complex number z/w where z is this Complex number
     */
    public ComplexNumber div(final ComplexNumber w) {
        final double i = getImaginary();
        final double r = getReal();
        final double den = Math.pow(w.mod(), 2);
        return new ComplexNumber((r * w.getReal() + i * w.getImaginary()) / den,
                (i * w.getReal() - r * w.getImaginary()) / den);
    }

    @Override
    public final ComplexNumber divide(final ComplexNumber value) {
        return this.multiply(value.reciprocal());
    }

    @Override
    public final ComplexNumber divide(final double value) {
        return this.divide(new ComplexNumber(value, 0.0));
    }

    @Override
    public boolean equals(final Object compareObject) {
        if (!(compareObject instanceof org.apache.commons.math3.complex.Complex))
            return false;

        final org.apache.commons.math3.complex.Complex compareComplex = (org.apache.commons.math3.complex.Complex) compareObject;
        if (compareComplex.getReal() != getReal())
            return false;

        return compareComplex.getImaginary() == getImaginary();
    }

    /**
     * Complex exponential (doesn't change this Complex number).
     *
     * @return exp(z) where z is this Complex number.
     */
    @Override
    public ComplexNumber exp() {
        final double r = getReal(), i = getImaginary();
        return new ComplexNumber(Math.exp(r) * Math.cos(i), Math.exp(r) * Math.sin(i));
    }

    @Override
    public int hashCode() {
        final int imaginaryHash = Double.valueOf(getImaginary()).hashCode();
        final int realHash = Double.valueOf(getReal()).hashCode();
        return (imaginaryHash * realHash) + realHash;
    }

    @Override
    public ComplexNumber hypot(final ComplexNumber operand) {
        return this.pow(2.0).add(operand.pow(2.0)).sqrt();
    }

    @Override
    public boolean isInfinite() {
        return Double.isInfinite(getReal()) || Double.isInfinite(getImaginary());
    }

    @Override
    public boolean isNaN() {
        return Double.isNaN(getReal()) || Double.isNaN(getImaginary());
    }

    @Override
    public final ComplexNumber log() {
        return new ComplexNumber(Math.log(this.absScalar()), Math.atan2(getImaginary(), getReal()));
    }

    /**
     * Principal branch of the Complex logarithm of this Complex number.
     * (doesn't change this Complex number). The principal branch is the branch
     * with -pi < arg <= pi.
     *
     * @return log(z) where z is this Complex number.
     */
    public ComplexNumber logPolar() {
        return new ComplexNumber(Math.log(this.mod()), this.arg());
    }

    /**
     * Subtraction of Complex numbers (doesn't change this Complex number). <br>
     * (x+i*y) - (s+i*t) = (x-s)+i*(y-t).
     *
     * @param w is the number to subtract.
     * @return z-w where z is this Complex number.
     */
    public ComplexNumber minus(final ComplexNumber w) {
        final double r = getReal(), i = getImaginary();
        return new ComplexNumber(r - w.getReal(), i - w.getImaginary());
    }

    /**
     * Modulus of this Complex number (the distance from the origin in polar
     * coordinates).
     *
     * @return |z| where z is this Complex number.
     */
    public double mod() {
        final double r = getReal(), i = getImaginary();
        if (r != 0 || i != 0) {
            return Math.sqrt(r * r + i * i);
        } else {
            return 0d;
        }
    }

    @Override
    public final ComplexNumber multiply(final ComplexNumber value) {
        final double r = getReal(), i = getImaginary();
        final double imaginary = getReal() * value.getImaginary() + getImaginary() * value.getReal();
        final double real = getReal() * value.getReal() - getImaginary() * value.getImaginary();
        return new ComplexNumber(real, imaginary);
    }

    @Override
    public final ComplexNumber multiply(final double value) {
        return new ComplexNumber(value * getReal(), value * getImaginary());
    }

    @Override
    public final ComplexNumber negate() {
        return new ComplexNumber(-getReal(), -getImaginary());
    }

    // Value between -pi and pi
    public final double phase() {
        return Math.atan2(getImaginary(), getReal());
    }

    /**
     * Addition of Complex numbers (doesn't change this Complex number). <br>
     * (x+i*y) + (s+i*t) = (x+s)+i*(y+t).
     *
     * @param w is the number to add.
     * @return z+w where z is this Complex number.
     */
    public ComplexNumber plus(final ComplexNumber w) {
        final double r = getReal();
        final double i = getImaginary();
        return new ComplexNumber(r + w.getReal(), i + w.getImaginary());
    }

    @Override
    public final ComplexNumber pow(final ComplexNumber exponent) {
        if (exponent == null)
            throw new IllegalArgumentException("exponent can not be null");

        return this.log().multiply(exponent).exp();
    }

    @Override
    public final ComplexNumber pow(final double exponent) {
        return this.log().multiply(exponent).exp();
    }

    @Override
    public final ComplexNumber reciprocal() {
        final double scale = (getReal() * getReal()) + (getImaginary() * getImaginary());
        return new ComplexNumber(getReal() / scale, -getImaginary() / scale);
    }

    @Override
    public List<ComplexNumber> root(final int number) {
        if (number <= 0)
            throw new IllegalArgumentException("number must be greater than 0");

        final List<ComplexNumber> result = new ArrayList<>();

        double inner = this.phase() / number;
        for (int nIndex = 0; nIndex < number; nIndex++) {
            result.add(new ComplexNumber(Math.cos(inner) * Math.pow(this.absScalar(), 1.0 / number),
                    Math.sin(inner) * Math.pow(this.absScalar(), 1.0 / number)));
            inner += 2 * Math.PI / number;
        }

        return Collections.unmodifiableList(result);
    }

    /**
     * Sine of this Complex number (doesn't change this Complex number). <br>
     * sin(z) = (exp(i*z)-exp(-i*z))/(2*i).
     *
     * @return sin(z) where z is this Complex number.
     */
    @Override
    public ComplexNumber sin() {
        final double r = getReal();
        final double i = getImaginary();
        return new ComplexNumber(cosh(i) * Math.sin(r), sinh(i) * Math.cos(r));
    }

    /**
     * Hyperbolic sine of this Complex number (doesn't change this Complex
     * number). <br>
     * sinh(z) = (exp(z)-exp(-z))/2.
     *
     * @return sinh(z) where z is this Complex number.
     */
    @Override
    public ComplexNumber sinh() {
        final double r = getReal();
        final double i = getImaginary();
        return new ComplexNumber(sinh(r) * Math.cos(i), cosh(r) * Math.sin(i));
    }

    // Real sinh function (used to compute complex trig functions)
    private static double sinh(final double theta) {
        return (Math.exp(theta) - Math.exp(-theta)) / 2;
    }

    @Override
    public final ComplexNumber sqrt() {
        // The square-root of the complex number (a + i b) is
        // sqrt(a + i b) = +/- (sqrt(radius + a) + i sqrt(radius - a) sign(b))
        // sqrt(2) / 2,
        // where radius = sqrt(a^2 + b^2).
        final double radius = Math.sqrt((getReal() * getReal()) + (getImaginary() * getImaginary()));
        final ComplexNumber intermediate = new ComplexNumber(Math.sqrt(radius + getReal()),
                Math.sqrt(radius + getReal()) * Math.signum(getImaginary()));
        return intermediate.multiply(Math.sqrt(2.0)).divide(2.0);
    }

    /**
     * Complex square root (doesn't change this complex number). Computes the
     * principal branch of the square root, which is the value with 0 <= arg <
     * pi.
     *
     * @return sqrt(z) where z is this Complex number.
     */
    public ComplexNumber sqrtPolar() {
        final double r = Math.sqrt(this.mod());
        final double theta = this.arg() / 2;
        return new ComplexNumber(r * Math.cos(theta), r * Math.sin(theta));
    }

    private ComplexNumber sqrt1Minus() {
        return (new ComplexNumber(1.0, 0.0)).subtract(this.multiply(this)).sqrt();
    }

    @Override
    public final ComplexNumber subtract(final ComplexNumber value) {
        final double r = getReal();
        final double i = getImaginary();
        return new ComplexNumber(getReal() - value.getReal(), getImaginary() - value.getImaginary());
    }

    @Override
    public final ComplexNumber subtract(final double value) {
        return this.subtract(new ComplexNumber(value, 0.0));
    }

    /**
     * Tangent of this Complex number (doesn't change this Complex number). <br>
     * tan(z) = sin(z)/cos(z).
     *
     * @return tan(z) where z is this Complex number.
     */
    @Override
    public ComplexNumber tan() {
        return (this.sin()).div(this.cos());
    }

    @Override
    public final ComplexNumber tanh() {
        final double denominator = Math.cosh(2.0 * getReal()) + Math.cos(2.0 * getImaginary());
        return new ComplexNumber(Math.sinh(2.0 * getReal()) / denominator,
                Math.sin(2.0 * getImaginary()) / denominator);
    }

    /**
     * Complex multiplication (doesn't change this Complex number).
     *
     * @param w is the number to multiply by.
     * @return z*w where z is this Complex number.
     */
    public ComplexNumber times(final ComplexNumber w) {
        final double r = getReal();
        final double i = getImaginary();
        return new ComplexNumber(r * w.getReal() - i * w.getImaginary(), r * w.getImaginary() + i * w.getReal());
    }

    @Override
    public String toString() {
        if (getImaginary() == 0)
            return getReal() + "0";
        if (getReal() == 0)
            return getImaginary() + "i";
        if (getImaginary() < 0)
            return getReal() + " - " + getImaginary() + 'i';
        return getReal() + " + " + getImaginary() + 'i';
    }

    /**
     * String representation of this Complex number.
     *
     * @return x+i*y, x-i*y, x, or i*y as appropriate.
     */
    public String toString2() {
        final double r = getReal();
        final double i = getImaginary();

        if (r != 0 && i > 0) {
            return r + " + " + i + 'i';
        }
        if (r != 0 && i < 0) {
            return r + " - " + (-i) + 'i';
        }
        if (i == 0) {
            return String.valueOf(r);
        }
        if (r == 0) {
            return i + "i";
        }
        // shouldn't get here (unless Inf or NaN)
        return r + " + i*" + i;

    }

    @Override
    public syncleus.dann.math.Field<ComplexNumber> field() {
        return Field.FIELD;
    }

}