DoubleSummary.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-4.2.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 
025 import java.io.Serializable;
026 import java.util.DoubleSummaryStatistics;
027 import java.util.function.ToDoubleFunction;
028 import java.util.stream.Collector;
029 
030 import io.jenetics.internal.math.DoubleAdder;
031 
032 /**
033  <i>Value</i> objects which contains statistical summary information.
034  *
035  @see java.util.DoubleSummaryStatistics
036  *
037  * @implNote
038  * This class is immutable and thread-safe.
039  *
040  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
041  @since 3.0
042  @version 3.0
043  */
044 public final class DoubleSummary implements Serializable {
045 
046     private static final long serialVersionUID = 1L;
047 
048     private final long _count;
049     private final double _min;
050     private final double _max;
051     private final double _sum;
052     private final double _mean;
053 
054     /**
055      * Create an immutable object which contains statistical summary values.
056      *
057      @param count the count of values recorded
058      @param min the minimum value
059      @param max the maximum value
060      @param sum the sum of the recorded values
061      @param mean the arithmetic mean of values
062      */
063     private DoubleSummary(
064         final long count,
065         final double min,
066         final double max,
067         final double sum,
068         final double mean
069     ) {
070         _count = count;
071         _min = min;
072         _max = max;
073         _sum = sum;
074         _mean = mean;
075     }
076 
077     /**
078      * Returns the count of values recorded.
079      *
080      @return the count of recorded values
081      */
082     public long getCount() {
083         return _count;
084     }
085 
086     /**
087      * Return the minimum value recorded, or {@code Double.POSITIVE_INFINITY} if
088      * no values have been recorded.
089      *
090      @return the minimum value, or {@code Double.POSITIVE_INFINITY} if none
091      */
092     public double getMin() {
093         return _min;
094     }
095 
096     /**
097      * Return the maximum value recorded, or {@code Double.NEGATIVE_INFINITY} if
098      * no values have been recorded.
099      *
100      @return the maximum value, or {@code Double.NEGATIVE_INFINITY} if none
101      */
102     public double getMax() {
103         return _max;
104     }
105 
106     /**
107      * Return the sum of values recorded, or zero if no values have been
108      * recorded.
109      *
110      @return the sum of values, or zero if none
111      */
112     public double getSum() {
113         return _sum;
114     }
115 
116     /**
117      * Return the arithmetic mean of values recorded, or zero if no values have
118      * been recorded.
119      *
120      @return the arithmetic mean of values, or zero if none
121      */
122     public double getMean() {
123         return _mean;
124     }
125 
126     @Override
127     public int hashCode() {
128         int hash = 17;
129         hash += 33*_count + 37;
130         hash += 33*Double.hashCode(_sum37;
131         hash += 33*Double.hashCode(_min37;
132         hash += 33*Double.hashCode(_max37;
133         hash += 33*Double.hashCode(_mean37;
134         return hash;
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             getCount(), getMin(), getMax(), getSum(), getMean()
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 (int i = 0; i < values.length; ++i) {
248                 if (values[i< min) {
249                     min = values[i];
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 (int i = 0; i < values.length; ++i) {
273                 if (values[i> max) {
274                     max = values[i];
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 }