LongMomentStatistics.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.7.0).
003  * Copyright (c) 2007-2016 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@gmx.at)
019  */
020 package org.jenetics.stat;
021 
022 import static java.lang.Math.max;
023 import static java.lang.Math.min;
024 import static java.util.Objects.requireNonNull;
025 
026 import java.util.function.IntConsumer;
027 import java.util.function.LongConsumer;
028 import java.util.function.ToLongFunction;
029 import java.util.stream.Collector;
030 
031 /**
032  * A state object for collecting statistics such as count, min, max, sum, mean,
033  * variance, skewness and kurtosis. The design of this class is similar to the
034  * design of the {@link java.util.LongSummaryStatistics} class.
035  <p>
036  * This class is designed to work with (though does not require) streams. For
037  * example, you can compute moments-statistics on a stream of longs with:
038  <pre>{@code
039  * final LongStream stream = ...
040  * final LongMomentStatistics statistics = stream.collect(
041  *         LongMomentStatistics::new,
042  *         LongMomentStatistics::accept,
043  *         LongMomentStatistics::combine
044  *     );
045  * }</pre>
046  *
047  * For a non long stream, you can use a collector:
048  <pre>{@code
049  * final Stream<SomeObject> stream = ...
050  * final LongMomentStatistics statistics = stream
051  *     .collect(toLongMomentStatistics(v -> v.longValue()));
052  * }</pre>
053  *
054  <p>
055  <b>Implementation note:</b>
056  <i>This implementation is not thread safe. However, it is safe to use
057  {@link #toLongMomentStatistics(ToLongFunction)}  on a parallel stream, because the parallel
058  * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
059  * provides the necessary partitioning, isolation, and merging of results for
060  * safe and efficient parallel execution.</i>
061  *
062  @see java.util.LongSummaryStatistics
063  @see org.jenetics.stat.LongMoments
064  @see <a href="http://people.xiph.org/~tterribe/notes/homs.html">
065  *      Computing Higher-Order Moments Online</a>
066  *
067  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
068  @since 3.0
069  @version 3.7
070  */
071 public class LongMomentStatistics
072     extends MomentStatistics
073     implements LongConsumer, IntConsumer
074 {
075 
076     private long _min = Long.MAX_VALUE;
077     private long _max = Long.MIN_VALUE;
078     private long _sum = 0L;
079 
080     /**
081      * Create an empty moments object.
082      */
083     public LongMomentStatistics() {
084     }
085 
086     /**
087      * Records a new value into the moments information
088      *
089      @param value the input {@code value}
090      */
091     @Override
092     public void accept(final long value) {
093         super.accept(value);
094         _min = min(_min, value);
095         _max = max(_max, value);
096         _sum += value;
097     }
098 
099     /**
100      * Records a new value into the moments information
101      *
102      @param value the input {@code value}
103      */
104     @Override
105     public void accept(final int value) {
106         accept((long)value);
107     }
108 
109     /**
110      * Combine two {@code LongMoments} statistic objects.
111      *
112      @param other the other {@code LongMoments} statistics to combine with
113      *        {@code this} one.
114      @return {@code this} statistics object
115      @throws java.lang.NullPointerException if the other statistical summary
116      *         is {@code null}.
117      */
118     public LongMomentStatistics combine(final LongMomentStatistics other) {
119         super.combine(other);
120         _min = min(_min, other._min);
121         _max = max(_max, other._max);
122         _sum += other._sum;
123 
124         return this;
125     }
126 
127     /**
128      * Return the minimum value recorded, or {@code Long.MAX_VALUE} if no
129      * values have been recorded.
130      *
131      @return the minimum value, or {@code Long.MAX_VALUE} if none
132      */
133     public long getMin() {
134         return _min;
135     }
136 
137     /**
138      * Return the maximum value recorded, or {@code Long.MIN_VALUE} if no
139      * values have been recorded.
140      *
141      @return the maximum value, or {@code Long.MIN_VALUE} if none
142      */
143     public long getMax() {
144         return _max;
145     }
146 
147     /**
148      * Return the sum of values recorded, or zero if no values have been
149      * recorded.
150      *
151      @return the sum of values, or zero if none
152      */
153     public long getSum() {
154         return _sum;
155     }
156 
157     /**
158      * Compares the state of two {@code LongMomentStatistics} objects. This is
159      * a replacement for the {@link #equals(Object)} which is not advisable to
160      * implement for this mutable object. If two object have the same state, it
161      * has still the same state when updated with the same value.
162      <pre>{@code
163      * final LongMomentStatistics lms1 = ...;
164      * final LongMomentStatistics lms2 = ...;
165      *
166      * if (lms1.sameState(lms2)) {
167      *     final long value = random.nextInt(1_000_000);
168      *     lms1.accept(value);
169      *     lms2.accept(value);
170      *
171      *     assert lms1.sameState(lms2);
172      *     assert lms2.sameState(lms1);
173      *     assert lms1.sameState(lms1);
174      * }
175      * }</pre>
176      *
177      @since 3.7
178      *
179      @param other the other object for the test
180      @return {@code true} the {@code this} and the {@code other} objects have
181      *         the same state, {@code false} otherwise
182      */
183     public boolean sameState(final LongMomentStatistics other) {
184         return _min == other._min &&
185             _max == other._max &&
186             _sum == other._sum &&
187             super.sameState(other);
188     }
189 
190     @Override
191     public String toString() {
192         return String.format(
193             "LongMomentStatistics[N=%d, ∧=%s, ∨=%s, Σ=%s, μ=%s, s²=%s, S=%s, K=%s]",
194             getCount(), getMin(), getMax(), getSum(),
195             getMean(), getVariance(), getSkewness(), getKurtosis()
196         );
197     }
198 
199     /**
200      * Return a {@code Collector} which applies an long-producing mapping
201      * function to each input element, and returns moments-statistics for the
202      * resulting values.
203      *
204      <pre>{@code
205      * final Stream<SomeObject> stream = ...
206      * final LongMomentStatistics statistics = stream
207      *     .collect(toLongMomentStatistics(v -> v.longValue()));
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 moments-statistics reduction
213      @throws java.lang.NullPointerException if the given {@code mapper} is
214      *         {@code null}
215      */
216     public static <T> Collector<T, ?, LongMomentStatistics>
217     toLongMomentStatistics(final ToLongFunction<? super T> mapper) {
218         requireNonNull(mapper);
219         return Collector.of(
220             LongMomentStatistics::new,
221             (r, t-> r.accept(mapper.applyAsLong(t)),
222             LongMomentStatistics::combine
223         );
224     }
225 
226 }