001/*
002 * Java Genetic Algorithm Library (jenetics-2.0.2).
003 * Copyright (c) 2007-2014 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 */
020package org.jenetics.util;
021
022import static java.lang.String.format;
023import static java.util.Objects.requireNonNull;
024import static org.jenetics.internal.util.object.eq;
025
026import java.util.Iterator;
027import java.util.concurrent.Executor;
028
029import org.jenetics.internal.util.Concurrency;
030import org.jenetics.internal.util.HashBuilder;
031
032/**
033 * Collection of some general purpose Accumulators and some static helper classes
034 * for accumulating.
035 *
036 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
037 * @since 1.0
038 * @version 2.0 &mdash; <em>$Date: 2014-04-11 $</em>
039 */
040public final class accumulators extends StaticObject {
041        private accumulators() {}
042
043        public static final Accumulator<Object> NULL = new Accumulator<Object>() {
044                @Override
045                public void accumulate(final Object value) {
046                }
047        };
048
049        /**
050         * Calculates min value.
051         *
052         * <p>
053         * <strong>Note that this implementation is not synchronized.</strong> If
054         * multiple threads access this object concurrently, and at least one of the
055         * threads modifies it, it must be synchronized externally.
056         *
057         * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
058         * @since 1.0
059         * @version 1.0 &ndash; <em>$Date: 2014-04-11 $</em>
060         */
061        public static final class Min<C extends Comparable<? super C>>
062                extends MappedAccumulator<C>
063        {
064                private C _min;
065
066                /**
067                 * Create a new Min accumulator.
068                 */
069                public Min() {
070                }
071
072                /**
073                 * Copy constructor.
074                 *
075                 * @param min the accumulator to copy.
076                 * @throws NullPointerException if {@code min} is {@code null}.
077                 */
078                public Min(final Min<C> min) {
079                        requireNonNull(min, "Min");
080                        _samples = min._samples;
081                        _min = min._min;
082                }
083
084                /**
085                 * Return the min value, accumulated so far.
086                 *
087                 * @return the min value, accumulated so far.
088                 */
089                public C getMin() {
090                        return _min;
091                }
092
093                /**
094                 * @throws NullPointerException if the given {@code value} is {@code null}.
095                 */
096                @Override
097                public void accumulate(final C value) {
098                        if (_min == null) {
099                                _min = value;
100                        } else {
101                                if (value.compareTo(_min) < 0) {
102                                        _min = value;
103                                }
104                        }
105
106                        ++_samples;
107                }
108
109                @Override
110                public int hashCode() {
111                        return HashBuilder.of(getClass()).and(super.hashCode()).and(_min).value();
112                }
113
114                @Override
115                public boolean equals(final Object obj) {
116                        if (obj == this) {
117                                return true;
118                        }
119                        if (obj == null || obj.getClass() != getClass()) {
120                                return false;
121                        }
122
123                        final Min<?> min = (Min<?>)obj;
124                        return super.equals(obj) && eq(_min, min._min);
125                }
126
127                @Override
128                public String toString() {
129                        return format(
130                                        "%s[samples=%d, min=%s]",
131                                        getClass().getSimpleName(), getSamples(), getMin()
132                                );
133                }
134
135                @Override
136                public Min<C> clone() {
137                        return (Min<C>)super.clone();
138                }
139        }
140
141
142        /**
143         * Calculates max value.
144         *
145         * <p>
146         * <strong>Note that this implementation is not synchronized.</strong> If
147         * multiple threads access this object concurrently, and at least one of the
148         * threads modifies it, it must be synchronized externally.
149         *
150         * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
151         * @since 1.0
152         * @version 1.0 &ndash; <em>$Date: 2014-04-11 $</em>
153         */
154        public static final class Max<C extends Comparable<? super C>>
155                extends MappedAccumulator<C>
156        {
157                private C _max;
158
159                /**
160                 * Create a new Max accumulator.
161                 */
162                public Max() {
163                }
164
165                /**
166                 * Copy constructor.
167                 *
168                 * @param max the accumulator to copy.
169                 * @throws NullPointerException if {@code max} is {@code null}.
170                 */
171                public Max(final Max<C> max) {
172                        requireNonNull(max, "Max");
173                        _samples = max._samples;
174                        _max = max._max;
175                }
176
177                /**
178                 * Return the max value, accumulated so far.
179                 *
180                 * @return the max value, accumulated so far.
181                 */
182                public C getMax() {
183                        return _max;
184                }
185
186                /**
187                 * @throws NullPointerException if the given {@code value} is {@code null}.
188                 */
189                @Override
190                public void accumulate(final C value) {
191                        if (_max == null) {
192                                _max = value;
193                        } else {
194                                if (value.compareTo(_max) > 0) {
195                                        _max = value;
196                                }
197                        }
198
199                        ++_samples;
200                }
201
202                @Override
203                public int hashCode() {
204                        return HashBuilder.of(getClass()).and(super.hashCode()).and(_max).value();
205                }
206
207                @Override
208                public boolean equals(final Object obj) {
209                        if (obj == this) {
210                                return true;
211                        }
212                        if (obj == null || obj.getClass() != getClass()) {
213                                return false;
214                        }
215
216                        final Max<?> max = (Max<?>)obj;
217                        return super.equals(obj) && eq(_max, max._max);
218                }
219
220                @Override
221                public String toString() {
222                        return format(
223                                        "%s[samples=%d, max=%s]",
224                                        getClass().getSimpleName(), getSamples(), getMax()
225                                );
226                }
227
228                @Override
229                public Max<C> clone() {
230                        return (Max<C>)super.clone();
231                }
232        }
233
234
235        /**
236         * Calculates min and max values.
237         *
238         * <p>
239         * <strong>Note that this implementation is not synchronized.</strong> If
240         * multiple threads access this object concurrently, and at least one of the
241         * threads modifies it, it must be synchronized externally.
242         *
243         * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
244         * @since 1.0
245         * @version 1.0 &ndash; <em>$Date: 2014-04-11 $</em>
246         */
247        public static final class MinMax<C extends Comparable<? super C>>
248                extends MappedAccumulator<C>
249        {
250                private C _min;
251                private C _max;
252
253                /**
254                 * Create a new min-max accumulator.
255                 */
256                public MinMax() {
257                }
258
259                /**
260                 * Copy constructor.
261                 *
262                 * @param mm the accumulator to copy.
263                 * @throws NullPointerException if {@code mm} is {@code null}.
264                 */
265                public MinMax(final MinMax<C> mm) {
266                        requireNonNull(mm, "MinMax");
267                        _samples = mm._samples;
268                        _min = mm._min;
269                        _max = mm._max;
270                }
271
272                /**
273                 * Return the min value, accumulated so far.
274                 *
275                 * @return the min value, accumulated so far.
276                 */
277                public C getMin() {
278                        return _min;
279                }
280
281                /**
282                 * Return the max value, accumulated so far.
283                 *
284                 * @return the max value, accumulated so far.
285                 */
286                public C getMax() {
287                        return _max;
288                }
289
290                /**
291                 * @throws NullPointerException if the given {@code value} is {@code null}.
292                 */
293                @Override
294                public void accumulate(final C value) {
295                        if (_min == null) {
296                                _min = value;
297                                _max = value;
298                        } else {
299                                if (value.compareTo(_min) < 0) {
300                                        _min = value;
301                                } else if (value.compareTo(_max) > 0) {
302                                        _max = value;
303                                }
304                        }
305
306                        ++_samples;
307                }
308
309                @Override
310                public int hashCode() {
311                        return HashBuilder.of(getClass()).
312                                        and(super.hashCode()).
313                                        and(_min).
314                                        and(_max).value();
315                }
316
317                @Override
318                public boolean equals(final Object obj) {
319                        if (obj == this) {
320                                return true;
321                        }
322                        if (obj == null || obj.getClass() != getClass()) {
323                                return false;
324                        }
325
326                        final MinMax<?> mm = (MinMax<?>)obj;
327                        return super.equals(obj) && eq(_min, mm._min) && eq(_max, mm._max);
328                }
329
330                @Override
331                public String toString() {
332                        return format(
333                                        "%s[samples=%d, min=%s, max=%s]",
334                                        getClass().getSimpleName(), getSamples(), getMin(), getMax()
335                                );
336                }
337
338                @Override
339                public MinMax<C> clone() {
340                        return (MinMax<C>)super.clone();
341                }
342        }
343
344        /**
345         * Calls the {@link Accumulator#accumulate(Object)} method of all given
346         * {@code accumulators} with each value of the given {@code values}. The
347         * accumulation is done in parallel.
348         *
349         * @param <T> the value type.
350         * @param values the values to accumulate.
351         * @param accus the accumulators to apply.
352         * @throws NullPointerException if one of the given arguments is {@code null}.
353         */
354        public static <T> void accumulate(
355                final Executor executor,
356                final Iterable<? extends T> values,
357                final Seq<? extends Accumulator<? super T>> accus
358        ) {
359                switch (accus.length()) {
360                case 1:
361                        accumulate(
362                                values,
363                                accus.get(0)
364                        );
365                        break;
366                case 2:
367                        accumulate(
368                                executor,
369                                values,
370                                accus.get(0),
371                                accus.get(1)
372                        );
373                        break;
374                case 3:
375                        accumulate(
376                                executor,
377                                values,
378                                accus.get(0),
379                                accus.get(1),
380                                accus.get(2)
381                        );
382                        break;
383                case 4:
384                        accumulate(
385                                executor,
386                                values,
387                                accus.get(0),
388                                accus.get(1),
389                                accus.get(2),
390                                accus.get(3)
391                        );
392                        break;
393                case 5:
394                        accumulate(
395                                executor,
396                                values,
397                                accus.get(0),
398                                accus.get(1),
399                                accus.get(2),
400                                accus.get(3),
401                                accus.get(4)
402                        );
403                        break;
404                default:
405                        try (Concurrency c = Concurrency.with(executor)) {
406                                c.execute(accus.map(AccumulatorToRunnable(values)).asList());
407                        }
408                }
409        }
410
411        private static <T> Function<Accumulator<? super T>, Runnable>
412        AccumulatorToRunnable(final Iterable<? extends T> values) {
413                return new Function<Accumulator<? super T>, Runnable>() {
414                        @Override
415                        public Runnable apply(final Accumulator<? super T> accumulator) {
416                                return new Acc<>(values, accumulator);
417                        }
418                };
419        }
420
421        /**
422         * Calls the {@link Accumulator#accumulate(Object)} method of all given
423         * {@code accumulators} with each value of the given {@code values}. The
424         * accumulation is done in parallel.
425         *
426         * @param <T> the value type.
427         * @param values the values to accumulate.
428         * @param accus the accumulators to apply.
429         * @throws NullPointerException if one of the given arguments is {@code null}.
430         */
431        @SafeVarargs
432        public static <T> void accumulate(
433                final Executor executor,
434                final Iterable<? extends T> values,
435                final Accumulator<? super T>... accus
436        ) {
437                accumulate(executor, values, Array.of(accus));
438        }
439
440        /**
441         * Calls the {@link Accumulator#accumulate(Object)} method of the given
442         * {@code accumulator} with each value of the given {@code values}.
443         *
444         * @param <T> the value type.
445         * @param values the values to accumulate.
446         * @param a the accumulator.
447         * @throws NullPointerException if one of the given arguments is {@code null}.
448         */
449        public static <T> void accumulate(
450                final Iterator<? extends T> values,
451                final Accumulator<? super T> a
452        ) {
453                while (values.hasNext()) {
454                        a.accumulate(values.next());
455                }
456        }
457
458        /**
459         * Calls the {@link Accumulator#accumulate(Object)} method of the given
460         * {@code accumulator} with each value of the given {@code values}.
461         *
462         * @param <T> the value type.
463         * @param values the values to accumulate.
464         * @param a the accumulator.
465         * @throws NullPointerException if one of the given arguments is {@code null}.
466         */
467        public static <T> void accumulate(
468                final Iterable<? extends T> values,
469                final Accumulator<? super T> a
470        ) {
471                for (final T value : values) {
472                        a.accumulate(value);
473                }
474        }
475
476        /**
477         * Calls the {@link Accumulator#accumulate(Object)} method of all given
478         * {@code accumulators} with each value of the given {@code values}. The
479         * accumulation is done in parallel.
480         *
481         * @param <T> the value type.
482         * @param values the values to accumulate.
483         * @param a1 the first accumulator.
484         * @param a2 the second accumulator.
485         * @throws NullPointerException if one of the given arguments is {@code null}.
486         */
487        public static <T> void accumulate(
488                final Executor executor,
489                final Iterable<? extends T> values,
490                final Accumulator<? super T> a1,
491                final Accumulator<? super T> a2
492        ) {
493                try (Concurrency c = Concurrency.with(executor)) {
494                        c.execute(new Acc<>(values, a1));
495                        c.execute(new Acc<>(values, a2));
496                }
497        }
498
499        /**
500         * Calls the {@link Accumulator#accumulate(Object)} method of all given
501         * {@code accumulators} with each value of the given {@code values}. The
502         * accumulation is done in parallel.
503         *
504         * @param <T> the value type.
505         * @param values the values to accumulate.
506         * @param a1 the first accumulator.
507         * @param a2 the second accumulator.
508         * @param a3 the third accumulator
509         * @throws NullPointerException if one of the given arguments is {@code null}.
510         */
511        public static <T> void accumulate(
512                final Executor executor,
513                final Iterable<? extends T> values,
514                final Accumulator<? super T> a1,
515                final Accumulator<? super T> a2,
516                final Accumulator<? super T> a3
517        ) {
518                try (Concurrency c = Concurrency.with(executor)) {
519                        c.execute(new Acc<>(values, a1));
520                        c.execute(new Acc<>(values, a2));
521                        c.execute(new Acc<>(values, a3));
522                }
523        }
524
525        /**
526         * Calls the {@link Accumulator#accumulate(Object)} method of all given
527         * {@code accumulators} with each value of the given {@code values}. The
528         * accumulation is done in parallel.
529         *
530         * @param <T> the value type.
531         * @param values the values to accumulate.
532         * @param a1 the first accumulator.
533         * @param a2 the second accumulator.
534         * @param a3 the third accumulator.
535         * @param a4 the fourth accumulator.
536         * @throws NullPointerException if one of the given arguments is {@code null}.
537         */
538        public static <T> void accumulate(
539                final Executor executor,
540                final Iterable<? extends T> values,
541                final Accumulator<? super T> a1,
542                final Accumulator<? super T> a2,
543                final Accumulator<? super T> a3,
544                final Accumulator<? super T> a4
545        ) {
546                try (Concurrency c = Concurrency.with(executor)) {
547                        c.execute(new Acc<>(values, a1));
548                        c.execute(new Acc<>(values, a2));
549                        c.execute(new Acc<>(values, a3));
550                        c.execute(new Acc<>(values, a4));
551                }
552        }
553
554        /**
555         * Calls the {@link Accumulator#accumulate(Object)} method of all given
556         * {@code accumulators} with each value of the given {@code values}. The
557         * accumulation is done in parallel.
558         *
559         * @param <T> the value type.
560         * @param values the values to accumulate.
561         * @param a1 the first accumulator.
562         * @param a2 the second accumulator.
563         * @param a3 the third accumulator.
564         * @param a4 the fourth accumulator.
565         * @param a5 the fifth accumulator.
566         * @throws NullPointerException if one of the given arguments is {@code null}.
567         */
568        public static <T> void accumulate(
569                final Executor executor,
570                final Iterable<? extends T> values,
571                final Accumulator<? super T> a1,
572                final Accumulator<? super T> a2,
573                final Accumulator<? super T> a3,
574                final Accumulator<? super T> a4,
575                final Accumulator<? super T> a5
576        ) {
577                try (Concurrency c = Concurrency.with(executor)) {
578                        c.execute(new Acc<>(values, a1));
579                        c.execute(new Acc<>(values, a2));
580                        c.execute(new Acc<>(values, a3));
581                        c.execute(new Acc<>(values, a4));
582                        c.execute(new Acc<>(values, a5));
583                }
584        }
585
586        private static final class Acc<T> implements Runnable {
587                private final Iterable<? extends T> _values;
588                private final Accumulator<? super T> _accumulator;
589
590                public Acc(
591                        final Iterable<? extends T> values,
592                        final Accumulator<? super T> accumulator
593                ) {
594                        _values = values;
595                        _accumulator = accumulator;
596                }
597
598                @Override
599                public void run() {
600                        for (final T value : _values) {
601                                _accumulator.accumulate(value);
602                        }
603                }
604        }
605
606}