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 2024/01/05 16:13:39 UTC
(commons-statistics) 01/02: STATISTICS-84: Reuse Sum instance when creating MEAN and SUM
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-statistics.git
commit c9077da40d52581be9246c356f1f0076c82b5d58
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Fri Jan 5 15:46:59 2024 +0000
STATISTICS-84: Reuse Sum instance when creating MEAN and SUM
---
.../statistics/descriptive/DoubleStatistics.java | 49 +++++++++++++++++-----
.../statistics/descriptive/FirstMoment.java | 10 ++++-
.../apache/commons/statistics/descriptive/Sum.java | 16 +++++--
.../descriptive/SumOfCubedDeviations.java | 30 ++++++++++++-
.../descriptive/SumOfFourthDeviations.java | 30 ++++++++++++-
.../descriptive/SumOfSquaredDeviations.java | 29 ++++++++++++-
6 files changed, 146 insertions(+), 18 deletions(-)
diff --git a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/DoubleStatistics.java b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/DoubleStatistics.java
index eee279f..44bcb90 100644
--- a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/DoubleStatistics.java
+++ b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/DoubleStatistics.java
@@ -18,6 +18,7 @@ package org.apache.commons.statistics.descriptive;
import java.util.Objects;
import java.util.Set;
+import java.util.function.BiFunction;
import java.util.function.DoubleConsumer;
import java.util.function.Function;
@@ -71,9 +72,9 @@ public final class DoubleStatistics implements DoubleConsumer {
/** The {@link Max} constructor. */
private Function<double[], Max> max;
/** The moment constructor. May return any instance of {@link FirstMoment}. */
- private Function<double[], FirstMoment> moment;
+ private BiFunction<org.apache.commons.numbers.core.Sum, double[], FirstMoment> moment;
/** The {@link Sum} constructor. */
- private Function<double[], Sum> sum;
+ private Function<org.apache.commons.numbers.core.Sum, Sum> sum;
/** The {@link Product} constructor. */
private Function<double[], Product> product;
/** The {@link SumOfSquares} constructor. */
@@ -129,7 +130,7 @@ public final class DoubleStatistics implements DoubleConsumer {
createMoment(2);
break;
case SUM:
- sum = Sum::of;
+ sum = Sum::new;
break;
case SUM_OF_SQUARES:
sumOfSquares = SumOfSquares::of;
@@ -150,14 +151,14 @@ public final class DoubleStatistics implements DoubleConsumer {
if (order > momentOrder) {
momentOrder = order;
if (order == 4) {
- moment = SumOfFourthDeviations::of;
+ moment = SumOfFourthDeviations::create;
} else if (order == 3) {
- moment = SumOfCubedDeviations::of;
+ moment = SumOfCubedDeviations::create;
} else if (order == 2) {
- moment = SumOfSquaredDeviations::of;
+ moment = SumOfSquaredDeviations::create;
} else {
// Assume order == 1
- moment = FirstMoment::of;
+ moment = FirstMoment::create;
}
}
}
@@ -195,12 +196,21 @@ public final class DoubleStatistics implements DoubleConsumer {
*/
public DoubleStatistics build(double... values) {
Objects.requireNonNull(values, "values");
+ // Create related statistics
+ FirstMoment m = null;
+ Sum sumStat = null;
+ if (moment != null || sum != null) {
+ final org.apache.commons.numbers.core.Sum s =
+ org.apache.commons.numbers.core.Sum.of(values);
+ m = create(moment, s, values);
+ sumStat = create(sum, s);
+ }
return new DoubleStatistics(
values.length,
create(min, values),
create(max, values),
- create(moment, values),
- create(sum, values),
+ m,
+ sumStat,
create(product, values),
create(sumOfSquares, values),
create(sumOfLogs, values),
@@ -210,17 +220,36 @@ public final class DoubleStatistics implements DoubleConsumer {
/**
* Creates the object from the {@code values}.
*
+ * @param <S> value type
* @param <T> object type
* @param constructor Constructor.
* @param values Values
* @return the instance
*/
- private static <T> T create(Function<double[], T> constructor, double[] values) {
+ private static <S, T> T create(Function<S, T> constructor, S values) {
if (constructor != null) {
return constructor.apply(values);
}
return null;
}
+
+ /**
+ * Creates the object from the values {@code r} and {@code s}.
+ *
+ * @param <R> value type
+ * @param <S> value type
+ * @param <T> object type
+ * @param constructor Constructor.
+ * @param r Value.
+ * @param s Value.
+ * @return the instance
+ */
+ private static <R, S, T> T create(BiFunction<R, S, T> constructor, R r, S s) {
+ if (constructor != null) {
+ return constructor.apply(r, s);
+ }
+ return null;
+ }
}
/**
diff --git a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/FirstMoment.java b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/FirstMoment.java
index 2ef8ad8..5466ff6 100644
--- a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/FirstMoment.java
+++ b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/FirstMoment.java
@@ -160,11 +160,19 @@ class FirstMoment implements DoubleConsumer {
* <p>Uses the provided {@code sum} if finite; otherwise reverts to using the rolling moment
* to protect from overflow and adds a second pass correction term.
*
+ * <p>This method is used by {@link DoubleStatistics} using a sum that can be reused
+ * for the {@link Sum} statistic.
+ *
* @param sum Sum of the values.
* @param values Values.
* @return {@code FirstMoment} instance.
*/
- private static FirstMoment create(org.apache.commons.numbers.core.Sum sum, double... values) {
+ static FirstMoment create(org.apache.commons.numbers.core.Sum sum, double[] values) {
+ // Protect against empty values
+ if (values.length == 0) {
+ return new FirstMoment();
+ }
+
final double s = sum.getAsDouble();
if (Double.isFinite(s)) {
return new FirstMoment(s / values.length, values.length);
diff --git a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/Sum.java b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/Sum.java
index 4b66236..9c666fe 100644
--- a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/Sum.java
+++ b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/Sum.java
@@ -52,14 +52,22 @@ package org.apache.commons.statistics.descriptive;
public final class Sum implements DoubleStatistic, StatisticAccumulator<Sum> {
/** {@link org.apache.commons.numbers.core.Sum Sum} used to compute the sum. */
- private final org.apache.commons.numbers.core.Sum delegate =
- org.apache.commons.numbers.core.Sum.create();
+ private final org.apache.commons.numbers.core.Sum delegate;
/**
* Create an instance.
*/
private Sum() {
- // No-op
+ this(org.apache.commons.numbers.core.Sum.create());
+ }
+
+ /**
+ * Create an instance using the specified {@code sum}.
+ *
+ * @param sum Sum.
+ */
+ Sum(org.apache.commons.numbers.core.Sum sum) {
+ delegate = sum;
}
/**
@@ -85,7 +93,7 @@ public final class Sum implements DoubleStatistic, StatisticAccumulator<Sum> {
* @return {@code Sum} instance.
*/
public static Sum of(double... values) {
- return Statistics.add(new Sum(), values);
+ return new Sum(org.apache.commons.numbers.core.Sum.of(values));
}
/**
diff --git a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfCubedDeviations.java b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfCubedDeviations.java
index a0741eb..df96614 100644
--- a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfCubedDeviations.java
+++ b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfCubedDeviations.java
@@ -130,7 +130,35 @@ class SumOfCubedDeviations extends SumOfSquaredDeviations {
if (values.length == 0) {
return new SumOfCubedDeviations();
}
- final SumOfSquaredDeviations ss = SumOfSquaredDeviations.of(values);
+ return create(SumOfSquaredDeviations.of(values), values);
+ }
+
+ /**
+ * Creates the sum of cubed deviations.
+ *
+ * <p>Uses the provided {@code sum} to create the first moment.
+ * This method is used by {@link DoubleStatistics} using a sum that can be reused
+ * for the {@link Sum} statistic.
+ *
+ * @param sum Sum of the values.
+ * @param values Values.
+ * @return {@code SumOfCubedDeviations} instance.
+ */
+ static SumOfCubedDeviations create(org.apache.commons.numbers.core.Sum sum, double[] values) {
+ if (values.length == 0) {
+ return new SumOfCubedDeviations();
+ }
+ return create(SumOfSquaredDeviations.create(sum, values), values);
+ }
+
+ /**
+ * Creates the sum of cubed deviations.
+ *
+ * @param ss Sum of squared deviations.
+ * @param values Values.
+ * @return {@code SumOfCubedDeviations} instance.
+ */
+ private static SumOfCubedDeviations create(SumOfSquaredDeviations ss, double[] values) {
// Edge cases
final double xbar = ss.getFirstMoment();
if (!Double.isFinite(xbar)) {
diff --git a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfFourthDeviations.java b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfFourthDeviations.java
index 57eb543..e3e97ba 100644
--- a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfFourthDeviations.java
+++ b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfFourthDeviations.java
@@ -122,7 +122,35 @@ class SumOfFourthDeviations extends SumOfCubedDeviations {
if (values.length == 0) {
return new SumOfFourthDeviations();
}
- final SumOfCubedDeviations sc = SumOfCubedDeviations.of(values);
+ return create(SumOfCubedDeviations.of(values), values);
+ }
+
+ /**
+ * Creates the sum of fourth deviations.
+ *
+ * <p>Uses the provided {@code sum} to create the first moment.
+ * This method is used by {@link DoubleStatistics} using a sum that can be reused
+ * for the {@link Sum} statistic.
+ *
+ * @param sum Sum of the values.
+ * @param values Values.
+ * @return {@code SumOfFourthDeviations} instance.
+ */
+ static SumOfFourthDeviations create(org.apache.commons.numbers.core.Sum sum, double[] values) {
+ if (values.length == 0) {
+ return new SumOfFourthDeviations();
+ }
+ return create(SumOfCubedDeviations.create(sum, values), values);
+ }
+
+ /**
+ * Creates the sum of fourth deviations.
+ *
+ * @param sc Sum of cubed deviations.
+ * @param values Values.
+ * @return {@code SumOfFourthDeviations} instance.
+ */
+ private static SumOfFourthDeviations create(SumOfCubedDeviations sc, double[] values) {
// Edge cases
final double xbar = sc.getFirstMoment();
if (!Double.isFinite(xbar) ||
diff --git a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfSquaredDeviations.java b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfSquaredDeviations.java
index 4a9860a..624b03f 100644
--- a/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfSquaredDeviations.java
+++ b/commons-statistics-descriptive/src/main/java/org/apache/commons/statistics/descriptive/SumOfSquaredDeviations.java
@@ -113,11 +113,38 @@ class SumOfSquaredDeviations extends FirstMoment {
if (values.length == 0) {
return new SumOfSquaredDeviations();
}
+ return create(FirstMoment.of(values), values);
+ }
+
+ /**
+ * Creates the sum of squared deviations.
+ *
+ * <p>Uses the provided {@code sum} to create the first moment.
+ * This method is used by {@link DoubleStatistics} using a sum that can be reused
+ * for the {@link Sum} statistic.
+ *
+ * @param sum Sum of the values.
+ * @param values Values.
+ * @return {@code SumOfSquaredDeviations} instance.
+ */
+ static SumOfSquaredDeviations create(org.apache.commons.numbers.core.Sum sum, double[] values) {
+ if (values.length == 0) {
+ return new SumOfSquaredDeviations();
+ }
+ return create(FirstMoment.create(sum, values), values);
+ }
+ /**
+ * Creates the sum of squared deviations.
+ *
+ * @param m1 First moment.
+ * @param values Values.
+ * @return {@code SumOfSquaredDeviations} instance.
+ */
+ private static SumOfSquaredDeviations create(FirstMoment m1, double[] values) {
// "Corrected two-pass algorithm"
// See: Chan et al (1983) Equation 1.7
- final FirstMoment m1 = FirstMoment.of(values);
final double xbar = m1.getFirstMoment();
if (!Double.isFinite(xbar)) {
return new SumOfSquaredDeviations(Double.NaN, m1);