MinMax.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.2.0).
003  * Copyright (c) 2007-2020 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 5.2
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      * Returns the count of values recorded.
101      *
102      @return the count of recorded values
103      */
104     public long count() {
105         return _count;
106     }
107 
108     /**
109      * Returns the count of values recorded.
110      *
111      @return the count of recorded values
112      @deprecated Use {@link #count()} instead
113      */
114     @Deprecated
115     public long getCount() {
116         return _count;
117     }
118 
119     /**
120      * Return the current minimal object or {@code null} if no element has been
121      * accepted yet.
122      *
123      @return the current minimal object
124      */
125     public C min() {
126         return _min;
127     }
128 
129     /**
130      * Return the current minimal object or {@code null} if no element has been
131      * accepted yet.
132      *
133      @return the current minimal object
134      @deprecated Use {@link #min()} instead
135      */
136     @Deprecated
137     public C getMin() {
138         return _min;
139     }
140 
141     /**
142      * Return the current maximal object or {@code null} if no element has been
143      * accepted yet.
144      *
145      @return the current maximal object
146      */
147     public C max() {
148         return _max;
149     }
150 
151     /**
152      * Return the current maximal object or {@code null} if no element has been
153      * accepted yet.
154      *
155      @return the current maximal object
156      @deprecated Use {@link #max()} instead
157      */
158     @Deprecated
159     public C getMax() {
160         return _max;
161     }
162 
163     /**
164      * Compares the state of two {@code LongMomentStatistics} objects. This is
165      * a replacement for the {@link #equals(Object)} which is not advisable to
166      * implement for this mutable object. If two object have the same state, it
167      * has still the same state when updated with the same value.
168      <pre>{@code
169      * final MinMax mm1 = ...;
170      * final MinMax mm2 = ...;
171      *
172      * if (mm1.sameState(mm2)) {
173      *     final long value = random.nextInt(1_000_000);
174      *     mm1.accept(value);
175      *     mm2.accept(value);
176      *
177      *     assert mm1.sameState(mm2);
178      *     assert mm2.sameState(mm1);
179      *     assert mm1.sameState(mm1);
180      * }
181      * }</pre>
182      *
183      @since 3.7
184      *
185      @param other the other object for the test
186      @return {@code true} the {@code this} and the {@code other} objects have
187      *         the same state, {@code false} otherwise
188      */
189     public boolean sameState(final MinMax<C> other) {
190         return this == other ||
191             Objects.equals(_min, other._min&&
192             Objects.equals(_max, other._max);
193     }
194 
195     @Override
196     public String toString() {
197         return format("MinMax[count=%d, min=%s, max=%s]", _count, _min, _max);
198     }
199 
200     /* *************************************************************************
201      *  Some static helper methods.
202      * ************************************************************************/
203 
204     /**
205      * Return the minimum of two values, according the given comparator.
206      * {@code null} values are allowed.
207      *
208      @param comp the comparator used for determining the min value
209      @param a the first value to compare
210      @param b the second value to compare
211      @param <T> the type of the compared objects
212      @return the minimum value, or {@code null} if both values are {@code null}.
213      *         If only one value is {@code null}, the non {@code null} values is
214      *         returned.
215      */
216     public static <T> T
217     min(final Comparator<? super T> comp, final T a, final T b) {
218         return a != null ? b != null ? comp.compare(a, b<= ? a : b : a : b;
219     }
220 
221     /**
222      * Return the maximum of two values, according the given comparator.
223      * {@code null} values are allowed.
224      *
225      @param comp the comparator used for determining the max value
226      @param a the first value to compare
227      @param b the second value to compare
228      @param <T> the type of the compared objects
229      @return the maximum value, or {@code null} if both values are {@code null}.
230      *         If only one value is {@code null}, the non {@code null} values is
231      *         returned.
232      */
233     public static <T> T
234     max(final Comparator<? super T> comp, final T a, final T b) {
235         return a != null ? b != null ? comp.compare(a, b>= ? a : b : a : b;
236     }
237 
238 
239     /* *************************************************************************
240      *  Some static factory methods.
241      * ************************************************************************/
242 
243     /**
244      * Return a {@code Collector} which calculates the minimum and maximum value.
245      * The given {@code comparator} is used for comparing two objects.
246      *
247      <pre>{@code
248      * final Comparator<SomeObject> comparator = ...
249      * final Stream<SomeObject> stream = ...
250      * final MinMax<SomeObject> moments = stream
251      *     .collect(doubleMoments.toMinMax(comparator));
252      * }</pre>
253      *
254      @param comparator the {@code Comparator} to use
255      @param <T> the type of the input elements
256      @return a {@code Collector} implementing the min-max reduction
257      @throws java.lang.NullPointerException if the given {@code mapper} is
258      *         {@code null}
259      */
260     public static <T> Collector<T, ?, MinMax<T>>
261     toMinMax(final Comparator<? super T> comparator) {
262         requireNonNull(comparator);
263         return Collector.of(
264             () -> MinMax.of(comparator),
265             MinMax::accept,
266             MinMax::combine
267         );
268     }
269 
270     /**
271      * Return a {@code Collector} which calculates the minimum and maximum value.
272      * The <i>reducing</i> objects must be comparable.
273      *
274      <pre>{@code
275      * final Stream<SomeObject> stream = ...
276      * final MinMax<SomeObject> moments = stream
277      *     .collect(doubleMoments.toMinMax(comparator));
278      * }</pre>
279      *
280      @param <C> the type of the input elements
281      @return a {@code Collector} implementing the min-max reduction
282      @throws java.lang.NullPointerException if the given {@code mapper} is
283      *         {@code null}
284      */
285     public static <C extends Comparable<? super C>>
286     Collector<C, ?, MinMax<C>> toMinMax() {
287         return toMinMax(Comparator.naturalOrder());
288     }
289 
290     /**
291      * Create a new {@code MinMax} <i>consumer</i> with the given
292      {@link java.util.Comparator}.
293      *
294      @param comparator the comparator used for comparing two elements
295      @param <T> the element type
296      @return a new {@code MinMax} <i>consumer</i>
297      @throws java.lang.NullPointerException if the {@code comparator} is
298      *         {@code null}.
299      */
300     public static <T> MinMax<T> of(final Comparator<? super T> comparator) {
301         return new MinMax<>(comparator);
302     }
303 
304     /**
305      * Create a new {@code MinMax} <i>consumer</i>.
306      *
307      @param <C> the element type
308      @return a new {@code MinMax} <i>consumer</i>
309      */
310     public static <C extends Comparable<? super C>> MinMax<C> of() {
311         return of(Comparator.naturalOrder());
312     }
313 
314     /**
315      * Return a new flat-mapper function, which guarantees a strictly increasing
316      * stream, from an arbitrarily ordered source stream. Note that this
317      * function doesn't sort the stream. It <em>just</em> skips the <em>out of
318      * order</em> elements.
319      *
320      <pre>{@code
321      * final ISeq<Integer> values = new Random().ints(0, 100)
322      *     .boxed()
323      *     .limit(100)
324      *     .flatMap(MinMax.toStrictlyIncreasing())
325      *     .collect(ISeq.toISeq());
326      *
327      * System.out.println(values);
328      * // [6,47,65,78,96,96,99]
329      * }</pre>
330      *
331      @since 5.0
332      *
333      @param <C> the comparable type
334      @return a new flat-mapper function
335      */
336     public static <C extends Comparable<? super C>>
337     Function<C, Stream<C>> toStrictlyIncreasing() {
338         return toStrictly(MinMax::max);
339     }
340 
341     /**
342      * Return a new flat-mapper function, which guarantees a strictly decreasing
343      * stream, from an arbitrarily ordered source stream. Note that this
344      * function doesn't sort the stream. It <em>just</em> skips the <em>out of
345      * order</em> elements.
346      *
347      <pre>{@code
348      * final ISeq<Integer> values = new Random().ints(0, 100)
349      *     .boxed()
350      *     .limit(100)
351      *     .flatMap(MinMax.toStrictlyDecreasing())
352      *     .collect(ISeq.toISeq());
353      *
354      * System.out.println(values);
355      * // [45,32,15,12,3,1]
356      * }</pre>
357      *
358      @since 5.0
359      *
360      @param <C> the comparable type
361      @return a new flat-mapper function
362      */
363     public static <C extends Comparable<? super C>>
364     Function<C, Stream<C>> toStrictlyDecreasing() {
365         return toStrictly(MinMax::min);
366     }
367 
368     private static <C>
369     Function<C, Stream<C>> toStrictly(final BinaryOperator<C> comp) {
370         return new Function<C, Stream<C>>() {
371             private C _best;
372 
373             @Override
374             public Stream<C> apply(final C result) {
375                 final C best = comp.apply(_best, result);
376 
377                 final Stream<C> stream = best == _best
378                     ? Stream.empty()
379                     : Stream.of(best);
380 
381                 _best = best;
382 
383                 return stream;
384             }
385         };
386     }
387 
388     private static <T extends Comparable<? super T>> T max(final T a, final T b) {
389         if (a == null && b == nullreturn null;
390         if (a == nullreturn b;
391         if (b == nullreturn a;
392         return a.compareTo(b>= ? a : b;
393     }
394 
395     private static <T extends Comparable<? super T>> T min(final T a, final T b) {
396         if (a == null && b == nullreturn null;
397         if (a == nullreturn b;
398         if (b == nullreturn a;
399         return a.compareTo(b<= ? a : b;
400     }
401 
402 }