DoubleMoments.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.util.Objects.requireNonNull;
023 import static io.jenetics.internal.util.Hashes.hash;
024 
025 import java.io.Serializable;
026 import java.util.function.ToDoubleFunction;
027 import java.util.stream.Collector;
028 
029 /**
030  <i>Value</i> objects which contains statistical moments.
031  *
032  @see io.jenetics.stat.DoubleMomentStatistics
033  *
034  * @implNote
035  * This class is immutable and thread-safe.
036  *
037  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
038  @since 3.0
039  @version 4.1
040  */
041 public final class DoubleMoments implements Serializable {
042 
043     private static final long serialVersionUID = 1L;
044 
045     private final long _count;
046     private final double _min;
047     private final double _max;
048     private final double _sum;
049     private final double _mean;
050     private final double _variance;
051     private final double _skewness;
052     private final double _kurtosis;
053 
054 
055     /**
056      * Create an immutable object which contains statistical 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      @param variance the variance of values
064      @param skewness the skewness of values
065      @param kurtosis the kurtosis of values
066      */
067     private DoubleMoments(
068         final long count,
069         final double min,
070         final double max,
071         final double sum,
072         final double mean,
073         final double variance,
074         final double skewness,
075         final double kurtosis
076     ) {
077         _count = count;
078         _min = min;
079         _max = max;
080         _sum = sum;
081         _mean = mean;
082         _variance = variance;
083         _skewness = skewness;
084         _kurtosis = kurtosis;
085     }
086 
087     /**
088      * Returns the count of values recorded.
089      *
090      @return the count of recorded values
091      */
092     public long getCount() {
093         return _count;
094     }
095 
096     /**
097      * Return the minimum value recorded, or {@code Double.POSITIVE_INFINITY} if
098      * no values have been recorded.
099      *
100      @return the minimum value, or {@code Integer.MAX_VALUE} if none
101      */
102     public double getMin() {
103         return _min;
104     }
105 
106     /**
107      * Return the maximum value recorded, or {@code Double.NEGATIVE_INFINITY} if
108      * no values have been recorded.
109      *
110      @return the maximum value, or {@code Integer.MIN_VALUE} if none
111      */
112     public double getMax() {
113         return _max;
114     }
115 
116     /**
117      * Return the sum of values recorded, or zero if no values have been
118      * recorded.
119      *
120      @return the sum of values, or zero if none
121      */
122     public double getSum() {
123         return _sum;
124     }
125 
126     /**
127      * Return the arithmetic mean of values recorded, or zero if no values have
128      * been recorded.
129      *
130      @return the arithmetic mean of values, or zero if none
131      */
132     public double getMean() {
133         return _mean;
134     }
135 
136     /**
137      * Return the variance of values recorded, or {@code Double.NaN} if no
138      * values have been recorded.
139      *
140      @return the variance of values, or {@code NaN} if none
141      */
142     public double getVariance() {
143         return _variance;
144     }
145 
146     /**
147      * Return the skewness of values recorded, or {@code Double.NaN} if less
148      * than two values have been recorded.
149      *
150      @see <a href="https://en.wikipedia.org/wiki/Skewness">Skewness</a>
151      *
152      @return the skewness of values, or {@code NaN} if less than two values
153      *         have been recorded
154      */
155     public double getSkewness() {
156         return _skewness;
157     }
158 
159     /**
160      * Return the kurtosis of values recorded, or {@code Double.NaN} if less
161      * than four values have been recorded.
162      *
163      @see <a href="https://en.wikipedia.org/wiki/Kurtosis">Kurtosis</a>
164      *
165      @return the kurtosis of values, or {@code NaN} if less than four values
166      *         have been recorded
167      */
168     public double getKurtosis() {
169         return _kurtosis;
170     }
171 
172     @Override
173     public int hashCode() {
174         return
175             hash(_count,
176             hash(_sum,
177             hash(_min,
178             hash(_max,
179             hash(_mean,
180             hash(_variance,
181             hash(_skewness,
182             hash(_kurtosis,
183             hash(getClass())))))))));
184     }
185 
186     @Override
187     public boolean equals(final Object obj) {
188         return obj == this ||
189             obj instanceof DoubleMoments &&
190             _count == ((DoubleMoments)obj)._count &&
191             Double.compare(_sum, ((DoubleMoments)obj)._sum== &&
192             Double.compare(_min, ((DoubleMoments)obj)._min== &&
193             Double.compare(_max, ((DoubleMoments)obj)._max== &&
194             Double.compare(_mean, ((DoubleMoments)obj)._mean== &&
195             Double.compare(_variance, ((DoubleMoments)obj)._variance== &&
196             Double.compare(_skewness, ((DoubleMoments)obj)._skewness== 0&&
197             Double.compare(_kurtosis, ((DoubleMoments)obj)._kurtosis== 0;
198     }
199 
200     @Override
201     public String toString() {
202         return String.format(
203             "DoubleMoments[N=%d, ∧=%s, ∨=%s, Σ=%s, μ=%s, s²=%s, S=%s, K=%s]",
204             getCount(), getMin(), getMax(), getSum(),
205             getMean(), getVariance(), getSkewness(), getKurtosis()
206         );
207     }
208 
209     /**
210      * Create an immutable object which contains statistical values.
211      *
212      @param count the count of values recorded
213      @param min the minimum value
214      @param max the maximum value
215      @param sum the sum of the recorded values
216      @param mean the arithmetic mean of values
217      @param variance the variance of values
218      @param skewness the skewness of values
219      @param kurtosis the kurtosis of values
220      @return an immutable object which contains statistical values
221      */
222     public static DoubleMoments of(
223         final long count,
224         final double min,
225         final double max,
226         final double sum,
227         final double mean,
228         final double variance,
229         final double skewness,
230         final double kurtosis
231     ) {
232         return new DoubleMoments(
233             count,
234             min,
235             max,
236             sum,
237             mean,
238             variance,
239             skewness,
240             kurtosis
241         );
242     }
243 
244     /**
245      * Return a new value object of the statistical moments, currently
246      * represented by the {@code statistics} object.
247      *
248      @param statistics the creating (mutable) statistics class
249      @return the statistical moments
250      */
251     public static DoubleMoments of(final DoubleMomentStatistics statistics) {
252         return new DoubleMoments(
253             statistics.getCount(),
254             statistics.getMin(),
255             statistics.getMax(),
256             statistics.getSum(),
257             statistics.getMean(),
258             statistics.getVariance(),
259             statistics.getSkewness(),
260             statistics.getKurtosis()
261         );
262     }
263 
264     /**
265      * Return a {@code Collector} which returns moments-statistics for the
266      * resulting values.
267      *
268      <pre>{@code
269      * final Stream<Double> stream = ...
270      * final DoubleMoments moments = stream.collect(toDoubleMoments()));
271      * }</pre>
272      *
273      @since 4.1
274      *
275      @param <N> the type of the input elements
276      @return a {@code Collector} implementing the moments-statistics reduction
277      */
278     public static <N extends Number> Collector<N, ?, DoubleMoments>
279     toDoubleMoments() {
280         return toDoubleMoments(Number::doubleValue);
281     }
282 
283     /**
284      * Return a {@code Collector} which applies an double-producing mapping
285      * function to each input element, and returns moments-statistics for the
286      * resulting values.
287      *
288      <pre>{@code
289      * final Stream<SomeObject> stream = ...
290      * final DoubleMoments moments = stream
291      *     .collect(toDoubleMoments(v -> v.doubleValue()));
292      * }</pre>
293      *
294      @param mapper a mapping function to apply to each element
295      @param <T> the type of the input elements
296      @return a {@code Collector} implementing the moments-statistics reduction
297      @throws java.lang.NullPointerException if the given {@code mapper} is
298      *         {@code null}
299      */
300     public static <T> Collector<T, ?, DoubleMoments>
301     toDoubleMoments(final ToDoubleFunction<? super T> mapper) {
302         requireNonNull(mapper);
303         return Collector.of(
304             DoubleMomentStatistics::new,
305             (a, b-> a.accept(mapper.applyAsDouble(b)),
306             DoubleMomentStatistics::combine,
307             DoubleMoments::of
308         );
309     }
310 
311 }