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