MinMax.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.1.0).
003  * Copyright (c) 2007-2019 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.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.BinaryOperator;
028 import java.util.function.Consumer;
029 import java.util.function.Function;
030 import java.util.stream.Collector;
031 import java.util.stream.Stream;
032 
033 /**
034  * This <i>consumer</i> class is used for calculating the min and max value
035  * according to the given {@code Comparator}.
036  <p>
037  * This class is designed to work with (though does not require) streams. For
038  * example, you can compute minimum and maximum values with:
039  <pre>{@code
040  * final Stream<Integer> stream = ...
041  * final MinMax<Integer> minMax = stream.collect(
042  *         MinMax::of,
043  *         MinMax::accept,
044  *         MinMax::combine
045  *     );
046  * }</pre>
047  *
048  * @implNote
049  * This implementation is not thread safe. However, it is safe to use on a
050  * parallel stream, because the parallel implementation of
051  {@link java.util.stream.Stream#collect Stream.collect()}provides the
052  * necessary partitioning, isolation, and merging of results for safe and
053  * efficient parallel execution.
054  *
055  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
056  @since 3.0
057  @version 3.7
058  */
059 public final class MinMax<C> implements Consumer<C> {
060 
061     private final Comparator<? super C> _comparator;
062 
063     private C _min;
064     private C _max;
065     private long _count = 0L;
066 
067     private MinMax(final Comparator<? super C> comparator) {
068         _comparator = requireNonNull(comparator);
069     }
070 
071     /**
072      * Accept the element for min-max calculation.
073      *
074      @param object the element to use for min-max calculation
075      */
076     @Override
077     public void accept(final C object) {
078         _min = min(_comparator, _min, object);
079         _max = max(_comparator, _max, object);
080         ++_count;
081     }
082 
083     /**
084      * Combine two {@code MinMax} objects.
085      *
086      @param other the other {@code MinMax} object to combine
087      @return {@code this}
088      @throws java.lang.NullPointerException if the {@code other} object is
089      *         {@code null}.
090      */
091     public MinMax<C> combine(final MinMax<C> other) {
092         _min = min(_comparator, _min, other._min);
093         _max = max(_comparator, _max, other._max);
094         _count += other._count;
095 
096         return this;
097     }
098 
099     /**
100      * Return the current minimal object or {@code null} if no element has been
101      * accepted yet.
102      *
103      @return the current minimal object
104      */
105     public C getMin() {
106         return _min;
107     }
108 
109     /**
110      * Return the current maximal object or {@code null} if no element has been
111      * accepted yet.
112      *
113      @return the current maximal object
114      */
115     public C getMax() {
116         return _max;
117     }
118 
119     /**
120      * Returns the count of values recorded.
121      *
122      @return the count of recorded values
123      */
124     public long getCount() {
125         return _count;
126     }
127 
128     /**
129      * Compares the state of two {@code LongMomentStatistics} objects. This is
130      * a replacement for the {@link #equals(Object)} which is not advisable to
131      * implement for this mutable object. If two object have the same state, it
132      * has still the same state when updated with the same value.
133      <pre>{@code
134      * final MinMax mm1 = ...;
135      * final MinMax mm2 = ...;
136      *
137      * if (mm1.sameState(mm2)) {
138      *     final long value = random.nextInt(1_000_000);
139      *     mm1.accept(value);
140      *     mm2.accept(value);
141      *
142      *     assert mm1.sameState(mm2);
143      *     assert mm2.sameState(mm1);
144      *     assert mm1.sameState(mm1);
145      * }
146      * }</pre>
147      *
148      @since 3.7
149      *
150      @param other the other object for the test
151      @return {@code true} the {@code this} and the {@code other} objects have
152      *         the same state, {@code false} otherwise
153      */
154     public boolean sameState(final MinMax<C> other) {
155         return this == other ||
156             Objects.equals(_min, other._min&&
157             Objects.equals(_max, other._max);
158     }
159 
160     @Override
161     public String toString() {
162         return format("MinMax[count=%d, min=%s, max=%s]", _count, _min, _max);
163     }
164 
165     /* *************************************************************************
166      *  Some static helper methods.
167      * ************************************************************************/
168 
169     /**
170      * Return the minimum of two values, according the given comparator.
171      * {@code null} values are allowed.
172      *
173      @param comp the comparator used for determining the min value
174      @param a the first value to compare
175      @param b the second value to compare
176      @param <T> the type of the compared objects
177      @return the minimum value, or {@code null} if both values are {@code null}.
178      *         If only one value is {@code null}, the non {@code null} values is
179      *         returned.
180      */
181     public static <T> T
182     min(final Comparator<? super T> comp, final T a, final T b) {
183         return a != null ? b != null ? comp.compare(a, b<= ? a : b : a : b;
184     }
185 
186     /**
187      * Return the maximum of two values, according the given comparator.
188      * {@code null} values are allowed.
189      *
190      @param comp the comparator used for determining the max value
191      @param a the first value to compare
192      @param b the second value to compare
193      @param <T> the type of the compared objects
194      @return the maximum value, or {@code null} if both values are {@code null}.
195      *         If only one value is {@code null}, the non {@code null} values is
196      *         returned.
197      */
198     public static <T> T
199     max(final Comparator<? super T> comp, final T a, final T b) {
200         return a != null ? b != null ? comp.compare(a, b>= ? a : b : a : b;
201     }
202 
203 
204     /* *************************************************************************
205      *  Some static factory methods.
206      * ************************************************************************/
207 
208     /**
209      * Return a {@code Collector} which calculates the minimum and maximum value.
210      * The given {@code comparator} is used for comparing two objects.
211      *
212      <pre>{@code
213      * final Comparator<SomeObject> comparator = ...
214      * final Stream<SomeObject> stream = ...
215      * final MinMax<SomeObject> moments = stream
216      *     .collect(doubleMoments.toMinMax(comparator));
217      * }</pre>
218      *
219      @param comparator the {@code Comparator} to use
220      @param <T> the type of the input elements
221      @return a {@code Collector} implementing the min-max reduction
222      @throws java.lang.NullPointerException if the given {@code mapper} is
223      *         {@code null}
224      */
225     public static <T> Collector<T, ?, MinMax<T>>
226     toMinMax(final Comparator<? super T> comparator) {
227         requireNonNull(comparator);
228         return Collector.of(
229             () -> MinMax.of(comparator),
230             MinMax::accept,
231             MinMax::combine
232         );
233     }
234 
235     /**
236      * Return a {@code Collector} which calculates the minimum and maximum value.
237      * The <i>reducing</i> objects must be comparable.
238      *
239      <pre>{@code
240      * final Stream<SomeObject> stream = ...
241      * final MinMax<SomeObject> moments = stream
242      *     .collect(doubleMoments.toMinMax(comparator));
243      * }</pre>
244      *
245      @param <C> the type of the input elements
246      @return a {@code Collector} implementing the min-max reduction
247      @throws java.lang.NullPointerException if the given {@code mapper} is
248      *         {@code null}
249      */
250     public static <C extends Comparable<? super C>>
251     Collector<C, ?, MinMax<C>> toMinMax() {
252         return toMinMax(Comparator.naturalOrder());
253     }
254 
255     /**
256      * Create a new {@code MinMax} <i>consumer</i> with the given
257      {@link java.util.Comparator}.
258      *
259      @param comparator the comparator used for comparing two elements
260      @param <T> the element type
261      @return a new {@code MinMax} <i>consumer</i>
262      @throws java.lang.NullPointerException if the {@code comparator} is
263      *         {@code null}.
264      */
265     public static <T> MinMax<T> of(final Comparator<? super T> comparator) {
266         return new MinMax<>(comparator);
267     }
268 
269     /**
270      * Create a new {@code MinMax} <i>consumer</i>.
271      *
272      @param <C> the element type
273      @return a new {@code MinMax} <i>consumer</i>
274      */
275     public static <C extends Comparable<? super C>> MinMax<C> of() {
276         return of(Comparator.naturalOrder());
277     }
278 
279     /**
280      * Return a new flat-mapper function, which guarantees a strictly increasing
281      * stream, from an arbitrarily ordered source stream. Note that this
282      * function doesn't sort the stream. It <em>just</em> skips the <em>out of
283      * order</em> elements.
284      *
285      <pre>{@code
286      * final ISeq<Integer> values = new Random().ints(0, 100)
287      *     .boxed()
288      *     .limit(100)
289      *     .flatMap(MinMax.toStrictlyIncreasing())
290      *     .collect(ISeq.toISeq());
291      *
292      * System.out.println(values);
293      * // [6,47,65,78,96,96,99]
294      * }</pre>
295      *
296      @since 5.0
297      *
298      @param <C> the comparable type
299      @return a new flat-mapper function
300      */
301     public static <C extends Comparable<? super C>>
302     Function<C, Stream<C>> toStrictlyIncreasing() {
303         return toStrictly(MinMax::max);
304     }
305 
306     /**
307      * Return a new flat-mapper function, which guarantees a strictly decreasing
308      * stream, from an arbitrarily ordered source stream. Note that this
309      * function doesn't sort the stream. It <em>just</em> skips the <em>out of
310      * order</em> elements.
311      *
312      <pre>{@code
313      * final ISeq<Integer> values = new Random().ints(0, 100)
314      *     .boxed()
315      *     .limit(100)
316      *     .flatMap(MinMax.toStrictlyDecreasing())
317      *     .collect(ISeq.toISeq());
318      *
319      * System.out.println(values);
320      * // [45,32,15,12,3,1]
321      * }</pre>
322      *
323      @since 5.0
324      *
325      @param <C> the comparable type
326      @return a new flat-mapper function
327      */
328     public static <C extends Comparable<? super C>>
329     Function<C, Stream<C>> toStrictlyDecreasing() {
330         return toStrictly(MinMax::min);
331     }
332 
333     private static <C>
334     Function<C, Stream<C>> toStrictly(final BinaryOperator<C> comp) {
335         return new Function<C, Stream<C>>() {
336             private C _best;
337 
338             @Override
339             public Stream<C> apply(final C result) {
340                 final C best = comp.apply(_best, result);
341 
342                 final Stream<C> stream = best == _best
343                     ? Stream.empty()
344                     : Stream.of(best);
345 
346                 _best = best;
347 
348                 return stream;
349             }
350         };
351     }
352 
353     private static <T extends Comparable<? super T>> T max(final T a, final T b) {
354         if (a == null && b == nullreturn null;
355         if (a == nullreturn b;
356         if (b == nullreturn a;
357         return a.compareTo(b>= ? a : b;
358     }
359 
360     private static <T extends Comparable<? super T>> T min(final T a, final T b) {
361         if (a == null && b == nullreturn null;
362         if (a == nullreturn b;
363         if (b == nullreturn a;
364         return a.compareTo(b<= ? a : b;
365     }
366 
367 }