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