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) == 0 &&
144 Double.compare(_min, ((DoubleSummary)obj)._min) == 0 &&
145 Double.compare(_max, ((DoubleSummary)obj)._max) == 0 &&
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 > 0 ? sum(values)/values.length : NaN;
309 }
310
311 }
|