MinMax.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.9.0).
003  * Copyright (c) 2007-2017 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.String.format;
023 import static java.util.Objects.requireNonNull;
024 
025 import java.util.Comparator;
026 import java.util.Objects;
027 import java.util.function.Consumer;
028 import java.util.stream.Collector;
029 
030 /**
031  * This <i>consumer</i> class is used for calculating the min and max value
032  * according to the given {@code Comparator}.
033  <p>
034  * This class is designed to work with (though does not require) streams. For
035  * example, you can compute minimum and maximum values with:
036  <pre>{@code
037  * final Stream<Integer> stream = ...
038  * final MinMax<Integer> minMax = stream.collect(
039  *         MinMax::of,
040  *         MinMax::accept,
041  *         MinMax::combine
042  *     );
043  * }</pre>
044  *
045  <p>
046  <b>Implementation note:</b>
047  <i>This implementation is not thread safe. However, it is safe to use on a
048  * parallel stream, because the parallel implementation of
049  {@link java.util.stream.Stream#collect Stream.collect()}provides the
050  * necessary partitioning, isolation, and merging of results for safe and
051  * efficient parallel execution.</i>
052  *
053  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
054  @since 3.0
055  @version 3.7
056  */
057 public final class MinMax<C> implements Consumer<C> {
058 
059     private final Comparator<? super C> _comparator;
060 
061     private C _min;
062     private C _max;
063     private long _count = 0L;
064 
065     private MinMax(final Comparator<? super C> comparator) {
066         _comparator = requireNonNull(comparator);
067     }
068 
069     /**
070      * Accept the element for min-max calculation.
071      *
072      @param object the element to use for min-max calculation
073      */
074     @Override
075     public void accept(final C object) {
076         _min = min(_comparator, _min, object);
077         _max = max(_comparator, _max, object);
078         ++_count;
079     }
080 
081     /**
082      * Combine two {@code MinMax} objects.
083      *
084      @param other the other {@code MinMax} object to combine
085      @return {@code this}
086      @throws java.lang.NullPointerException if the {@code other} object is
087      *         {@code null}.
088      */
089     public MinMax<C> combine(final MinMax<C> other) {
090         _min = min(_comparator, _min, other._min);
091         _max = max(_comparator, _max, other._max);
092         _count += other._count;
093 
094         return this;
095     }
096 
097     /**
098      * Return the current minimal object or {@code null} if no element has been
099      * accepted yet.
100      *
101      @return the current minimal object
102      */
103     public C getMin() {
104         return _min;
105     }
106 
107     /**
108      * Return the current maximal object or {@code null} if no element has been
109      * accepted yet.
110      *
111      @return the current maximal object
112      */
113     public C getMax() {
114         return _max;
115     }
116 
117     /**
118      * Returns the count of values recorded.
119      *
120      @return the count of recorded values
121      */
122     public long getCount() {
123         return _count;
124     }
125 
126     /**
127      * Compares the state of two {@code LongMomentStatistics} objects. This is
128      * a replacement for the {@link #equals(Object)} which is not advisable to
129      * implement for this mutable object. If two object have the same state, it
130      * has still the same state when updated with the same value.
131      <pre>{@code
132      * final MinMax mm1 = ...;
133      * final MinMax mm2 = ...;
134      *
135      * if (mm1.sameState(mm2)) {
136      *     final long value = random.nextInt(1_000_000);
137      *     mm1.accept(value);
138      *     mm2.accept(value);
139      *
140      *     assert mm1.sameState(mm2);
141      *     assert mm2.sameState(mm1);
142      *     assert mm1.sameState(mm1);
143      * }
144      * }</pre>
145      *
146      @since 3.7
147      *
148      @param other the other object for the test
149      @return {@code true} the {@code this} and the {@code other} objects have
150      *         the same state, {@code false} otherwise
151      */
152     public boolean sameState(final MinMax<C> other) {
153         return Objects.equals(_min, other._min&&
154             Objects.equals(_max, other._max);
155     }
156 
157     @Override
158     public String toString() {
159         return format("MinMax[count=%d, min=%s, max=%s]", _count, _min, _max);
160     }
161 
162     /* *************************************************************************
163      *  Some static helper methods.
164      * ************************************************************************/
165 
166     /**
167      * Return the minimum of two values, according the given comparator.
168      * {@code null} values are allowed.
169      *
170      @param comp the comparator used for determining the min value
171      @param a the first value to compare
172      @param b the second value to compare
173      @param <T> the type of the compared objects
174      @return the minimum value, or {@code null} if both values are {@code null}.
175      *         If only one value is {@code null}, the non {@code null} values is
176      *         returned.
177      */
178     public static <T> T
179     min(final Comparator<? super T> comp, final T a, final T b) {
180         return a != null ? b != null ? comp.compare(a, b<= ? a : b : a : b;
181     }
182 
183     /**
184      * Return the maximum of two values, according the given comparator.
185      * {@code null} values are allowed.
186      *
187      @param comp the comparator used for determining the max value
188      @param a the first value to compare
189      @param b the second value to compare
190      @param <T> the type of the compared objects
191      @return the maximum value, or {@code null} if both values are {@code null}.
192      *         If only one value is {@code null}, the non {@code null} values is
193      *         returned.
194      */
195     public static <T> T
196     max(final Comparator<? super T> comp, final T a, final T b) {
197         return a != null ? b != null ? comp.compare(a, b>= ? a : b : a : b;
198     }
199 
200 
201     /* *************************************************************************
202      *  Some static factory methods.
203      * ************************************************************************/
204 
205     /**
206      * Return a {@code Collector} which calculates the minimum and maximum value.
207      * The given {@code comparator} is used for comparing two objects.
208      *
209      <pre>{@code
210      * final Comparator<SomeObject> comparator = ...
211      * final Stream<SomeObject> stream = ...
212      * final MinMax<SomeObject> moments = stream
213      *     .collect(doubleMoments.toMinMax(comparator));
214      * }</pre>
215      *
216      @param comparator the {@code Comparator} to use
217      @param <T> the type of the input elements
218      @return a {@code Collector} implementing the min-max reduction
219      @throws java.lang.NullPointerException if the given {@code mapper} is
220      *         {@code null}
221      */
222     public static <T> Collector<T, ?, MinMax<T>>
223     toMinMax(final Comparator<? super T> comparator) {
224         requireNonNull(comparator);
225         return Collector.of(
226             () -> MinMax.of(comparator),
227             MinMax::accept,
228             MinMax::combine
229         );
230     }
231 
232     /**
233      * Return a {@code Collector} which calculates the minimum and maximum value.
234      * The <i>reducing</i> objects must be comparable.
235      *
236      <pre>{@code
237      * final Stream<SomeObject> stream = ...
238      * final MinMax<SomeObject> moments = stream
239      *     .collect(doubleMoments.toMinMax(comparator));
240      * }</pre>
241      *
242      @param <C> the type of the input elements
243      @return a {@code Collector} implementing the min-max reduction
244      @throws java.lang.NullPointerException if the given {@code mapper} is
245      *         {@code null}
246      */
247     public static <C extends Comparable<? super C>>
248     Collector<C, ?, MinMax<C>> toMinMax() {
249         return toMinMax(Comparator.naturalOrder());
250     }
251 
252     /**
253      * Create a new {@code MinMax} <i>consumer</i> with the given
254      {@link java.util.Comparator}.
255      *
256      @param comparator the comparator used for comparing two elements
257      @param <T> the element type
258      @return a new {@code MinMax} <i>consumer</i>
259      @throws java.lang.NullPointerException if the {@code comparator} is
260      *         {@code null}.
261      */
262     public static <T> MinMax<T> of(final Comparator<? super T> comparator) {
263         return new MinMax<>(comparator);
264     }
265 
266     /**
267      * Create a new {@code MinMax} <i>consumer</i>.
268      *
269      @param <C> the element type
270      @return a new {@code MinMax} <i>consumer</i>
271      */
272     public static <C extends Comparable<? super C>> MinMax<C> of() {
273         return of(Comparator.naturalOrder());
274     }
275 
276 }