DoubleSummary.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.2.0).
003  * Copyright (c) 2007-2020 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.stat;
021 
022 import static java.lang.Double.NaN;
023 import static java.util.Objects.requireNonNull;
024 import static io.jenetics.internal.util.Hashes.hash;
025 
026 import java.io.Serializable;
027 import java.util.DoubleSummaryStatistics;
028 import java.util.function.ToDoubleFunction;
029 import java.util.stream.Collector;
030 
031 import io.jenetics.internal.math.DoubleAdder;
032 
033 /**
034  <i>Value</i> objects which contains statistical summary information.
035  *
036  @see java.util.DoubleSummaryStatistics
037  *
038  * @implNote
039  * This class is immutable and thread-safe.
040  *
041  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
042  @since 3.0
043  @version 5.2
044  */
045 public final /*record*/ class DoubleSummary implements Serializable {
046 
047     private static final long serialVersionUID = 1L;
048 
049     private final long _count;
050     private final double _min;
051     private final double _max;
052     private final double _sum;
053     private final double _mean;
054 
055     /**
056      * Create an immutable object which contains statistical summary values.
057      *
058      @param count the count of values recorded
059      @param min the minimum value
060      @param max the maximum value
061      @param sum the sum of the recorded values
062      @param mean the arithmetic mean of values
063      */
064     private DoubleSummary(
065         final long count,
066         final double min,
067         final double max,
068         final double sum,
069         final double mean
070     ) {
071         _count = count;
072         _min = min;
073         _max = max;
074         _sum = sum;
075         _mean = mean;
076     }
077 
078     /**
079      * Returns the count of values recorded.
080      *
081      @return the count of recorded values
082      */
083     public long count() {
084         return _count;
085     }
086 
087     /**
088      * Returns the count of values recorded.
089      *
090      @return the count of recorded values
091      @deprecated Use {@link #count()} instead
092      */
093     @Deprecated
094     public long getCount() {
095         return _count;
096     }
097 
098     /**
099      * Return the minimum value recorded, or {@code Double.POSITIVE_INFINITY} if
100      * no values have been recorded.
101      *
102      @return the minimum value, or {@code Double.POSITIVE_INFINITY} if none
103      */
104     public double min() {
105         return _min;
106     }
107 
108     /**
109      * Return the minimum value recorded, or {@code Double.POSITIVE_INFINITY} if
110      * no values have been recorded.
111      *
112      @return the minimum value, or {@code Double.POSITIVE_INFINITY} if none
113      @deprecated Use {@link #min()} instead
114      */
115     @Deprecated
116     public double getMin() {
117         return _min;
118     }
119 
120     /**
121      * Return the maximum value recorded, or {@code Double.NEGATIVE_INFINITY} if
122      * no values have been recorded.
123      *
124      @return the maximum value, or {@code Double.NEGATIVE_INFINITY} if none
125      */
126     public double max() {
127         return _max;
128     }
129 
130     /**
131      * Return the maximum value recorded, or {@code Double.NEGATIVE_INFINITY} if
132      * no values have been recorded.
133      *
134      @return the maximum value, or {@code Double.NEGATIVE_INFINITY} if none
135      @deprecated Use {@link #max()} instead
136      */
137     @Deprecated
138     public double getMax() {
139         return _max;
140     }
141 
142     /**
143      * Return the sum of values recorded, or zero if no values have been
144      * recorded.
145      *
146      @return the sum of values, or zero if none
147      */
148     public double sum() {
149         return _sum;
150     }
151 
152     /**
153      * Return the sum of values recorded, or zero if no values have been
154      * recorded.
155      *
156      @return the sum of values, or zero if none
157      @deprecated Use {@link #sum()} instead
158      */
159     @Deprecated
160     public double getSum() {
161         return _sum;
162     }
163 
164     /**
165      * Return the arithmetic mean of values recorded, or zero if no values have
166      * been recorded.
167      *
168      @return the arithmetic mean of values, or zero if none
169      */
170     public double mean() {
171         return _mean;
172     }
173 
174     /**
175      * Return the arithmetic mean of values recorded, or zero if no values have
176      * been recorded.
177      *
178      @return the arithmetic mean of values, or zero if none
179      @deprecated Use {@link #mean()} instead
180      */
181     @Deprecated
182     public double getMean() {
183         return _mean;
184     }
185 
186     @Override
187     public int hashCode() {
188         return
189             hash(_count,
190             hash(_sum,
191             hash(_min,
192             hash(_max,
193             hash(_mean)))));
194     }
195 
196     @Override
197     public boolean equals(final Object obj) {
198         return obj == this ||
199             obj instanceof DoubleSummary &&
200             _count == ((DoubleSummary)obj)._count &&
201             Double.compare(_sum, ((DoubleSummary)obj)._sum== &&
202             Double.compare(_min, ((DoubleSummary)obj)._min== &&
203             Double.compare(_max, ((DoubleSummary)obj)._max== &&
204             Double.compare(_mean, ((DoubleSummary)obj)._mean== 0;
205     }
206 
207     @Override
208     public String toString() {
209         return String.format(
210             "DoubleSummary[N=%d, ∧=%s, ∨=%s, Σ=%s, μ=%s]",
211             count(), min(), max(), sum(), mean()
212         );
213     }
214 
215     /**
216      * Create an immutable object which contains statistical summary values.
217      *
218      @param count the count of values recorded
219      @param min the minimum value
220      @param max the maximum value
221      @param sum the sum of the recorded values
222      @param mean the arithmetic mean of values
223      @return an immutable object which contains statistical summary values
224      */
225     public static DoubleSummary of(
226         final long count,
227         final double min,
228         final double max,
229         final double sum,
230         final double mean
231     ) {
232         return new DoubleSummary(
233             count,
234             min,
235             max,
236             sum,
237             mean
238         );
239     }
240 
241     /**
242      * Return a new value object of the statistical summary, currently
243      * represented by the {@code statistics} object.
244      *
245      @param statistics the creating (mutable) statistics class
246      @return the statistical moments
247      */
248     public static DoubleSummary of(final DoubleSummaryStatistics statistics) {
249         return new DoubleSummary(
250             statistics.getCount(),
251             statistics.getMin(),
252             statistics.getMax(),
253             statistics.getSum(),
254             statistics.getAverage()
255         );
256     }
257 
258     /**
259      * Return a {@code Collector} which applies an double-producing mapping
260      * function to each input element, and returns summary-statistics for the
261      * resulting values.
262      *
263      <pre>{@code
264      * final Stream<SomeObject> stream = ...
265      * final DoubleSummary summary = stream
266      *     .collect(toDoubleSummary(v -> v.doubleValue()));
267      * }</pre>
268      *
269      @param mapper a mapping function to apply to each element
270      @param <T> the type of the input elements
271      @return a {@code Collector} implementing the summary-statistics reduction
272      @throws java.lang.NullPointerException if the given {@code mapper} is
273      *         {@code null}
274      */
275     public static <T> Collector<T, ?, DoubleSummary>
276     toDoubleSummary(final ToDoubleFunction<? super T> mapper) {
277         requireNonNull(mapper);
278         return Collector.of(
279             DoubleSummaryStatistics::new,
280             (a, b-> a.accept(mapper.applyAsDouble(b)),
281             (a, b-> {a.combine(b)return a;},
282             DoubleSummary::of
283         );
284     }
285 
286 
287     /* *************************************************************************
288      * Some static helper methods.
289      **************************************************************************/
290 
291     /**
292      * Return the minimum value of the given double array.
293      *
294      @since 4.0
295      *
296      @param values the double array.
297      @return the minimum value or {@link Double#NaN} if the given array is
298      *         empty.
299      @throws NullPointerException if the given array is {@code null}.
300      */
301     public static double min(final double[] values) {
302         double min = NaN;
303         if (values.length > 0) {
304             min = values[0];
305 
306             for (double value : values) {
307                 if (value < min) {
308                     min = value;
309                 }
310             }
311         }
312 
313         return min;
314     }
315 
316     /**
317      * Return the maximum value of the given double array.
318      *
319      @since 4.0
320      *
321      @param values the double array.
322      @return the maximum value or {@link Double#NaN} if the given array is
323      *         empty.
324      @throws NullPointerException if the given array is {@code null}.
325      */
326     public static double max(final double[] values) {
327         double max = NaN;
328         if (values.length > 0) {
329             max = values[0];
330 
331             for (double value : values) {
332                 if (value > max) {
333                     max = value;
334                 }
335             }
336         }
337 
338         return max;
339     }
340 
341     /**
342      * Return the sum of the given double array.
343      *
344      @since 4.0
345      *
346      @param values the values to sum up.
347      @return the sum of the given {@code values}.
348      @throws NullPointerException if the given array is {@code null}.
349      */
350     public static double sum(final double[] values) {
351         return DoubleAdder.sum(values);
352     }
353 
354     /**
355      * Returns a double describing the arithmetic mean of the values, or
356      {@link Double#NaN} if the {@code values} array is empty.
357      *
358      @since 4.0
359      *
360      @param values the values to calculate the mean of
361      @return the arithmetic mean of the given {@code values} or
362      *         {@link Double#NaN} if the {@code values} array is empty
363      @throws NullPointerException if the given array is {@code null}.
364      */
365     public static double mean(final double[] values) {
366         return values.length > ? sum(values)/values.length : NaN;
367     }
368 
369 }