DoubleSummary.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-6.2.0).
003  * Copyright (c) 2007-2021 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 6.0
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      * Return the minimum value recorded, or {@code Double.POSITIVE_INFINITY} if
089      * no values have been recorded.
090      *
091      @return the minimum value, or {@code Double.POSITIVE_INFINITY} if none
092      */
093     public double min() {
094         return _min;
095     }
096 
097     /**
098      * Return the maximum value recorded, or {@code Double.NEGATIVE_INFINITY} if
099      * no values have been recorded.
100      *
101      @return the maximum value, or {@code Double.NEGATIVE_INFINITY} if none
102      */
103     public double max() {
104         return _max;
105     }
106 
107     /**
108      * Return the sum of values recorded, or zero if no values have been
109      * recorded.
110      *
111      @return the sum of values, or zero if none
112      */
113     public double sum() {
114         return _sum;
115     }
116 
117     /**
118      * Return the arithmetic mean of values recorded, or zero if no values have
119      * been recorded.
120      *
121      @return the arithmetic mean of values, or zero if none
122      */
123     public double mean() {
124         return _mean;
125     }
126 
127     @Override
128     public int hashCode() {
129         return
130             hash(_count,
131             hash(_sum,
132             hash(_min,
133             hash(_max,
134             hash(_mean)))));
135     }
136 
137     @Override
138     public boolean equals(final Object obj) {
139         return obj == this ||
140             obj instanceof DoubleSummary &&
141             _count == ((DoubleSummary)obj)._count &&
142             Double.compare(_sum, ((DoubleSummary)obj)._sum== &&
143             Double.compare(_min, ((DoubleSummary)obj)._min== &&
144             Double.compare(_max, ((DoubleSummary)obj)._max== &&
145             Double.compare(_mean, ((DoubleSummary)obj)._mean== 0;
146     }
147 
148     @Override
149     public String toString() {
150         return String.format(
151             "DoubleSummary[N=%d, ∧=%s, ∨=%s, Σ=%s, μ=%s]",
152             count(), min(), max(), sum(), mean()
153         );
154     }
155 
156     /**
157      * Create an immutable object which contains statistical summary values.
158      *
159      @param count the count of values recorded
160      @param min the minimum value
161      @param max the maximum value
162      @param sum the sum of the recorded values
163      @param mean the arithmetic mean of values
164      @return an immutable object which contains statistical summary values
165      */
166     public static DoubleSummary of(
167         final long count,
168         final double min,
169         final double max,
170         final double sum,
171         final double mean
172     ) {
173         return new DoubleSummary(
174             count,
175             min,
176             max,
177             sum,
178             mean
179         );
180     }
181 
182     /**
183      * Return a new value object of the statistical summary, currently
184      * represented by the {@code statistics} object.
185      *
186      @param statistics the creating (mutable) statistics class
187      @return the statistical moments
188      */
189     public static DoubleSummary of(final DoubleSummaryStatistics statistics) {
190         return new DoubleSummary(
191             statistics.getCount(),
192             statistics.getMin(),
193             statistics.getMax(),
194             statistics.getSum(),
195             statistics.getAverage()
196         );
197     }
198 
199     /**
200      * Return a {@code Collector} which applies an double-producing mapping
201      * function to each input element, and returns summary-statistics for the
202      * resulting values.
203      *
204      <pre>{@code
205      * final Stream<SomeObject> stream = ...
206      * final DoubleSummary summary = stream
207      *     .collect(toDoubleSummary(v -> v.doubleValue()));
208      * }</pre>
209      *
210      @param mapper a mapping function to apply to each element
211      @param <T> the type of the input elements
212      @return a {@code Collector} implementing the summary-statistics reduction
213      @throws java.lang.NullPointerException if the given {@code mapper} is
214      *         {@code null}
215      */
216     public static <T> Collector<T, ?, DoubleSummary>
217     toDoubleSummary(final ToDoubleFunction<? super T> mapper) {
218         requireNonNull(mapper);
219         return Collector.of(
220             DoubleSummaryStatistics::new,
221             (a, b-> a.accept(mapper.applyAsDouble(b)),
222             (a, b-> {a.combine(b)return a;},
223             DoubleSummary::of
224         );
225     }
226 
227 
228     /* *************************************************************************
229      * Some static helper methods.
230      **************************************************************************/
231 
232     /**
233      * Return the minimum value of the given double array.
234      *
235      @since 4.0
236      *
237      @param values the double array.
238      @return the minimum value or {@link Double#NaN} if the given array is
239      *         empty.
240      @throws NullPointerException if the given array is {@code null}.
241      */
242     public static double min(final double[] values) {
243         double min = NaN;
244         if (values.length > 0) {
245             min = values[0];
246 
247             for (double value : values) {
248                 if (value < min) {
249                     min = value;
250                 }
251             }
252         }
253 
254         return min;
255     }
256 
257     /**
258      * Return the maximum value of the given double array.
259      *
260      @since 4.0
261      *
262      @param values the double array.
263      @return the maximum value or {@link Double#NaN} if the given array is
264      *         empty.
265      @throws NullPointerException if the given array is {@code null}.
266      */
267     public static double max(final double[] values) {
268         double max = NaN;
269         if (values.length > 0) {
270             max = values[0];
271 
272             for (double value : values) {
273                 if (value > max) {
274                     max = value;
275                 }
276             }
277         }
278 
279         return max;
280     }
281 
282     /**
283      * Return the sum of the given double array.
284      *
285      @since 4.0
286      *
287      @param values the values to sum up.
288      @return the sum of the given {@code values}.
289      @throws NullPointerException if the given array is {@code null}.
290      */
291     public static double sum(final double[] values) {
292         return DoubleAdder.sum(values);
293     }
294 
295     /**
296      * Returns a double describing the arithmetic mean of the values, or
297      {@link Double#NaN} if the {@code values} array is empty.
298      *
299      @since 4.0
300      *
301      @param values the values to calculate the mean of
302      @return the arithmetic mean of the given {@code values} or
303      *         {@link Double#NaN} if the {@code values} array is empty
304      @throws NullPointerException if the given array is {@code null}.
305      */
306     public static double mean(final double[] values) {
307         return values.length > ? sum(values)/values.length : NaN;
308     }
309 
310 }