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