/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.math;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.math.number.ComplexNumber;
import com.opengamma.util.ArgumentChecker;
/**
*
*/
public class ComplexMathUtils {
public static ComplexNumber add(final ComplexNumber z1, final ComplexNumber z2) {
ArgumentChecker.notNull(z1, "z1");
ArgumentChecker.notNull(z2, "z2");
return new ComplexNumber(z1.getReal() + z2.getReal(), z1.getImaginary() + z2.getImaginary());
}
public static ComplexNumber add(final ComplexNumber... z) {
ArgumentChecker.notNull(z, "z");
int n = z.length;
double res = 0.0;
double img = 0.0;
for (int i = 0; i < n; i++) {
res += z[i].getReal();
img += z[i].getImaginary();
}
return new ComplexNumber(res, img);
}
public static ComplexNumber add(final ComplexNumber z, final double x) {
ArgumentChecker.notNull(z, "z");
return new ComplexNumber(z.getReal() + x, z.getImaginary());
}
public static ComplexNumber add(final double x, final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
return new ComplexNumber(z.getReal() + x, z.getImaginary());
}
public static double arg(final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
return Math.atan2(z.getImaginary(), z.getReal());
}
public static ComplexNumber conjugate(final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
return new ComplexNumber(z.getReal(), -z.getImaginary());
}
public static ComplexNumber divide(final ComplexNumber z1, final ComplexNumber z2) {
ArgumentChecker.notNull(z1, "z1");
ArgumentChecker.notNull(z2, "z2");
final double a = z1.getReal();
final double b = z1.getImaginary();
final double c = z2.getReal();
final double d = z2.getImaginary();
if (Math.abs(c) > Math.abs(d)) {
final double dOverC = d / c;
final double denom = c + d * dOverC;
return new ComplexNumber((a + b * dOverC) / denom, (b - a * dOverC) / denom);
}
final double cOverD = c / d;
final double denom = c * cOverD + d;
return new ComplexNumber((a * cOverD + b) / denom, (b * cOverD - a) / denom);
}
public static ComplexNumber divide(final ComplexNumber z, final double x) {
ArgumentChecker.notNull(z, "z");
return new ComplexNumber(z.getReal() / x, z.getImaginary() / x);
}
public static ComplexNumber divide(final double x, final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
final double c = z.getReal();
final double d = z.getImaginary();
if (Math.abs(c) > Math.abs(d)) {
final double dOverC = d / c;
final double denom = c + d * dOverC;
return new ComplexNumber(x / denom, -x * dOverC / denom);
}
final double cOverD = c / d;
final double denom = c * cOverD + d;
return new ComplexNumber(x * cOverD / denom, -x / denom);
}
public static ComplexNumber exp(final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
final double mult = Math.exp(z.getReal());
return new ComplexNumber(mult * Math.cos(z.getImaginary()), mult * Math.sin(z.getImaginary()));
}
public static ComplexNumber inverse(final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
final double c = z.getReal();
final double d = z.getImaginary();
if (Math.abs(c) > Math.abs(d)) {
final double dOverC = d / c;
final double denom = c + d * dOverC;
return new ComplexNumber(1 / denom, -dOverC / denom);
}
final double cOverD = c / d;
final double denom = c * cOverD + d;
return new ComplexNumber(cOverD / denom, -1 / denom);
}
/**
* Returns the principal value of log, with z the principal argument of z defined to lie in the interval (-pi, pi]
* @param z ComplexNumber
* @return The log
*/
public static ComplexNumber log(final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
return new ComplexNumber(Math.log(Math.hypot(z.getReal(), z.getImaginary())), Math.atan2(z.getImaginary(), z.getReal()));
}
public static double mod(final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
return Math.hypot(z.getReal(), z.getImaginary());
}
public static ComplexNumber square(final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
final double a = z.getReal();
final double b = z.getImaginary();
return new ComplexNumber(a * a - b * b, 2 * a * b);
}
public static ComplexNumber multiply(final ComplexNumber z1, final ComplexNumber z2) {
ArgumentChecker.notNull(z1, "z1");
ArgumentChecker.notNull(z2, "z2");
final double a = z1.getReal();
final double b = z1.getImaginary();
final double c = z2.getReal();
final double d = z2.getImaginary();
return new ComplexNumber(a * c - b * d, a * d + b * c);
}
public static ComplexNumber multiply(final ComplexNumber... z) {
ArgumentChecker.notNull(z, "z");
final int n = z.length;
Validate.isTrue(n > 0, "nothing to multiply");
if (n == 1) {
return z[0];
} else if (n == 2) {
return multiply(z[0], z[1]);
} else {
ComplexNumber product = multiply(z[0], z[1]);
for (int i = 2; i < n; i++) {
product = multiply(product, z[i]);
}
return product;
}
}
public static ComplexNumber multiply(final double x, final ComplexNumber... z) {
ComplexNumber product = multiply(z);
return multiply(x, product);
}
public static ComplexNumber multiply(final ComplexNumber z, final double x) {
ArgumentChecker.notNull(z, "z");
return new ComplexNumber(z.getReal() * x, z.getImaginary() * x);
}
public static ComplexNumber multiply(final double x, final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
return new ComplexNumber(z.getReal() * x, z.getImaginary() * x);
}
public static ComplexNumber pow(final ComplexNumber z1, final ComplexNumber z2) {
ArgumentChecker.notNull(z1, "z1");
ArgumentChecker.notNull(z2, "z2");
final double mod = mod(z1);
final double arg = arg(z1);
final double mult = Math.pow(mod, z2.getReal()) * Math.exp(-z2.getImaginary() * arg);
final double theta = z2.getReal() * arg + z2.getImaginary() * Math.log(mod);
return new ComplexNumber(mult * Math.cos(theta), mult * Math.sin(theta));
}
public static ComplexNumber pow(final ComplexNumber z, final double x) {
final double mod = mod(z);
final double arg = arg(z);
final double mult = Math.pow(mod, x);
return new ComplexNumber(mult * Math.cos(x * arg), mult * Math.sin(x * arg));
}
public static ComplexNumber pow(final double x, final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
return pow(new ComplexNumber(x, 0), z);
}
public static ComplexNumber sqrt(final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
final double c = z.getReal();
final double d = z.getImaginary();
if (c == 0.0 && d == 0.0) {
return z;
}
double w;
if (Math.abs(c) > Math.abs(d)) {
final double dOverC = d / c;
w = Math.sqrt(Math.abs(c)) * Math.sqrt((1 + Math.sqrt(1 + dOverC * dOverC)) / 2);
} else {
final double cOverD = c / d;
w = Math.sqrt(Math.abs(d)) * Math.sqrt((Math.abs(cOverD) + Math.sqrt(1 + cOverD * cOverD)) / 2);
}
if (c >= 0.0) {
return new ComplexNumber(w, d / 2 / w);
}
if (d >= 0.0) {
return new ComplexNumber(d / 2 / w, w);
}
return new ComplexNumber(-d / 2 / w, -w);
}
public static ComplexNumber subtract(final ComplexNumber z1, final ComplexNumber z2) {
ArgumentChecker.notNull(z1, "z1");
ArgumentChecker.notNull(z2, "z2");
return new ComplexNumber(z1.getReal() - z2.getReal(), z1.getImaginary() - z2.getImaginary());
}
public static ComplexNumber subtract(final ComplexNumber z, final double x) {
ArgumentChecker.notNull(z, "z");
return new ComplexNumber(z.getReal() - x, z.getImaginary());
}
public static ComplexNumber subtract(final double x, final ComplexNumber z) {
ArgumentChecker.notNull(z, "z");
return new ComplexNumber(x - z.getReal(), -z.getImaginary());
}
}