You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/12/05 16:50:36 UTC
[commons-numbers] 02/08: Optimise mapping function to the positive
domain
This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git
commit cfb2719579a116123d6387091e0511ce74497cbd
Author: aherbert <ah...@apache.org>
AuthorDate: Thu Dec 5 10:37:39 2019 +0000
Optimise mapping function to the positive domain
---
.../apache/commons/numbers/complex/Complex.java | 146 ++++++++++++++-------
1 file changed, 102 insertions(+), 44 deletions(-)
diff --git a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
index 22fc471..70ba899 100644
--- a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
+++ b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
@@ -20,7 +20,6 @@ package org.apache.commons.numbers.complex;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
-import java.util.function.Function;
import java.util.function.UnaryOperator;
import org.apache.commons.numbers.core.Precision;
@@ -321,7 +320,7 @@ public final class Complex implements Serializable {
return new Complex(real + addend, imaginary);
}
- /**
+ /**
* Returns the conjugate of this complex number.
* The conjugate of {@code a + bi} is {@code a - bi}.
*
@@ -1044,10 +1043,10 @@ public final class Complex implements Serializable {
// asinh(conj(z)) = conj(asinh(z))
// and the odd function: f(z) = -f(-z)
// by always computing on a positive valued Complex number.
- final Function<Complex, Complex> fun = createPositiveDomainFunction();
- final Complex z = fun.apply(this);
+ final UnaryOperator<Complex> g = mapToPositiveDomain();
+ final Complex z = g.apply(this);
final Complex result = z.square().add(1).sqrt().add(z).log();
- return fun.apply(result);
+ return g.apply(result);
}
if (Double.isInfinite(imaginary)) {
return new Complex(Math.copySign(Double.POSITIVE_INFINITY, real), Math.copySign(PI_OVER_2, imaginary));
@@ -1104,10 +1103,10 @@ public final class Complex implements Serializable {
// atanh(conj(z)) = conj(atanh(z))
// and the odd function: f(z) = -f(-z)
// by always computing on a positive valued Complex number.
- final Function<Complex, Complex> fun = createPositiveDomainFunction();
- final Complex z = fun.apply(this);
+ final UnaryOperator<Complex> g = mapToPositiveDomain();
+ final Complex z = g.apply(this);
final Complex result = z.add(1).divide(z.subtractFromReal(1)).log().multiply(0.5);
- return fun.apply(result);
+ return g.apply(result);
}
if (Double.isInfinite(imaginary)) {
return new Complex(Math.copySign(0, real), Math.copySign(PI_OVER_2, imaginary));
@@ -1132,40 +1131,6 @@ public final class Complex implements Serializable {
}
/**
- * Creates a function to transform this Complex into a Complex with positive real and imaginary
- * components. This is used to maintain the conjugate equality and the oddness of a function
- * f(z) by always computing the result on positive valued input. Given:
- *
- * <pre>
- * conj(f(z)) = f(conj(z))
- * f(z) = -f(-z)
- * </pre>
- *
- * <p>The Complex can be tranformed to the positve domain using the a combination of
- * {@link #negate()} and/or {@link #conjugate()} functions, the function f(z) computed and
- * the result transformed back using the same mapping function to the original domain.</p>
- *
- * <p>If the Complex is already in the correct domain then this returns an identify
- * function.</p>
- *
- * @return the function
- */
- private Function<Complex, Complex> createPositiveDomainFunction() {
- Function<Complex, Complex> fun;
- if (negative(real)) {
- fun = Complex::negate;
- if (!negative(imaginary)) {
- fun = fun.andThen(Complex::conjugate);
- }
- } else if (negative(imaginary)) {
- fun = Complex::conjugate;
- } else {
- fun = UnaryOperator.identity();
- }
- return fun;
- }
-
- /**
* Compute the
* <a href="http://mathworld.wolfram.com/InverseHyperbolicCosine.html">
* inverse hyperbolic cosine</a> of this complex number.
@@ -1185,9 +1150,10 @@ public final class Complex implements Serializable {
}
// ISO C99: Preserve the equality
// acosh(conj(z)) = conj(acosh(z))
- final Complex z = negative(imaginary) ? conjugate() : this;
+ final UnaryOperator<Complex> g = mapImaginaryToPositiveDomain();
+ final Complex z = g.apply(this);
final Complex result = z.square().subtract(1).sqrt().add(z).log();
- return z == this ? result : result.conjugate();
+ return g.apply(result);
}
if (Double.isInfinite(imaginary)) {
return new Complex(Double.POSITIVE_INFINITY, Math.copySign(PI_OVER_2, imaginary));
@@ -1887,4 +1853,96 @@ public final class Complex implements Serializable {
return new NumberFormatException(sb.toString());
}
+
+ /**
+ * Creates a function to transform this Complex into a Complex with positive real and imaginary
+ * components. This is used to maintain the conjugate equality and the oddness of a function
+ * f(z) by always computing the result on positive valued input. Given:
+ *
+ * <pre>
+ * conj(f(z)) = f(conj(z))
+ * f(z) = -f(-z)
+ * </pre>
+ *
+ * <p>The Complex can be transformed to the positive domain using a combination of
+ * {@link #negate()} and/or {@link #conjugate()} functions, the function f(z) computed and
+ * the result transformed back using the same mapping function to the original domain.</p>
+ *
+ * <pre>
+ * g(z) = mapToPositiveDomain()
+ * f(z) = g(f(g(z)))
+ * </pre>
+ *
+ * <p>If the Complex is already in the correct domain then this returns an identify
+ * function. The function will be computed as:</p>
+ *
+ * <pre>
+ * real imaginary g(z)
+ * + + identity
+ * - + negateReal
+ * + - conjugate
+ * - - negate
+ * </pre>
+ *
+ * @return the function
+ */
+ private UnaryOperator<Complex> mapToPositiveDomain() {
+ if (negative(real)) {
+ return negative(imaginary) ? Complex::negate : Complex::negateReal;
+ } else if (negative(imaginary)) {
+ return Complex::conjugate;
+ }
+ return Complex::identity;
+ }
+
+ /**
+ * Creates a function to transform this Complex into a Complex with positive imaginary
+ * components. This is used to maintain the conjugate equality of a function
+ * f(z) by always computing the result on positive valued input. Given:
+ *
+ * <pre>
+ * conj(f(z)) = f(conj(z))
+ * </pre>
+ *
+ * <p>The Complex can be transformed to the positive domain using the {@link #conjugate()}
+ * function, the function f(z) computed and the result transformed back using the same
+ * mapping function to the original domain.</p>
+ *
+ * <pre>
+ * g(z) = mapImaginaryToPositiveDomain()
+ * f(z) = g(f(g(z)))
+ * </pre>
+ *
+ * <p>If the Complex is already in the correct domain then this returns an identify
+ * function. The function will be computed as:</p>
+ *
+ * <pre>
+ * imaginary g(z)
+ * + identity
+ * - conjugate
+ * </pre>
+ *
+ * @return the function
+ */
+ private UnaryOperator<Complex> mapImaginaryToPositiveDomain() {
+ return negative(imaginary) ? Complex::conjugate : Complex::identity;
+ }
+
+ /**
+ * Returns a {@code Complex} whose real value is negated.
+ *
+ * @return {@code Complex(-real, imaginary)}.
+ */
+ private Complex negateReal() {
+ return new Complex(-real, imaginary);
+ }
+
+ /**
+ * Returns this {@code Complex}.
+ *
+ * @return {@code this}.
+ */
+ private Complex identity() {
+ return this;
+ }
}