limit.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.5.0).
003  * Copyright (c) 2007-2016 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.engine;
021 
022 import static java.lang.String.format;
023 
024 import java.time.Clock;
025 import java.time.Duration;
026 import java.util.function.Predicate;
027 
028 import org.jenetics.internal.util.require;
029 
030 import org.jenetics.util.NanoClock;
031 
032 /**
033  * This class contains factory methods for creating predicates, which can be
034  * used for limiting the evolution stream.
035  *
036  @see EvolutionStream#limit(Predicate)
037  *
038  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
039  @since 3.0
040  @version 3.1
041  */
042 public final class limit {
043     private limit() {require.noInstance();}
044 
045     /**
046      * Return a predicate, which will truncate the evolution stream after the
047      * given number of generations. The returned predicate behaves like a call
048      * of the {@link java.util.stream.Stream#limit(long)} and exists for
049      <i>completeness</i> reasons.
050      *
051      @since 3.1
052      *
053      @param generation the number of generations after the evolution stream is
054      *        truncated
055      @return a predicate which truncates the evolution stream after the given
056      *        number of generations
057      @throws java.lang.IllegalArgumentException if the given {@code generation}
058      *         is smaller than zero.
059      */
060     public static Predicate<Object> byFixedGeneration(final long generation) {
061         if (generation < 0) {
062             throw new IllegalArgumentException(format(
063                 "The number of generations must greater than one, but was %d",
064                 generation
065             ));
066         }
067 
068         return new Predicate<Object>() {
069             private long _current;
070             @Override
071             public boolean test(final Object o) {
072                 return ++_current < generation;
073             }
074         };
075     }
076 
077     /**
078      * Return a predicate, which will truncate the evolution stream if no
079      * better phenotype could be found after the given number of
080      * {@code generations}.
081      *
082      <pre>{@code
083      * final Phenotype<DoubleGene, Double> result = engine.stream()
084      *      // Truncate the evolution stream after 5 "steady" generations.
085      *     .limit(bySteadyFitness(5))
086      *      // The evolution will stop after maximal 100 generations.
087      *     .limit(100)
088      *     .collect(toBestPhenotype());
089      * }</pre>
090      *
091      @param generations the number of <i>steady</i> generations
092      @param <C> the fitness type
093      @return a predicate which truncate the evolution stream if no better
094      *         phenotype could be found after a give number of
095      *         {@code generations}
096      @throws IllegalArgumentException if the generation is smaller than
097      *         one.
098      */
099     public static <C extends Comparable<? super C>>
100     Predicate<EvolutionResult<?, C>> bySteadyFitness(final int generations) {
101         return new SteadyFitnessLimit<>(generations);
102     }
103 
104     /**
105      * Return a predicate, which will truncate the evolution stream if the GA
106      * execution exceeds a given time duration. This predicate is (normally)
107      * used as safety net, for guaranteed stream truncation.
108      *
109      <pre>{@code
110      * final Phenotype<DoubleGene, Double> result = engine.stream()
111      *      // Truncate the evolution stream after 5 "steady" generations.
112      *     .limit(bySteadyFitness(5))
113      *      // The evolution will stop after maximal 500 ms.
114      *     .limit(byExecutionTime(Duration.ofMillis(500), Clock.systemUTC())
115      *     .collect(toBestPhenotype());
116      * }</pre>
117      *
118      @since 3.1
119      *
120      @param duration the duration after the evolution stream will be truncated
121      @param clock the clock used for measure the execution time
122      @return a predicate, which will truncate the evolution stream, based on
123      *         the exceeded execution time
124      @throws NullPointerException if one of the arguments is {@code null}
125      */
126     public static Predicate<Object>
127     byExecutionTime(final Duration duration, final Clock clock) {
128         return new ExecutionTimeLimit(duration, clock);
129     }
130 
131     /**
132      * Return a predicate, which will truncate the evolution stream if the GA
133      * execution exceeds a given time duration. This predicate is (normally)
134      * used as safety net, for guaranteed stream truncation.
135      *
136      <pre>{@code
137      * final Phenotype<DoubleGene, Double> result = engine.stream()
138      *      // Truncate the evolution stream after 5 "steady" generations.
139      *     .limit(bySteadyFitness(5))
140      *      // The evolution will stop after maximal 500 ms.
141      *     .limit(byExecutionTime(Duration.ofMillis(500))
142      *     .collect(toBestPhenotype());
143      * }</pre>
144      *
145      @since 3.1
146      *
147      @param duration the duration after the evolution stream will be truncated
148      @return a predicate, which will truncate the evolution stream, based on
149      *         the exceeded execution time
150      @throws NullPointerException if the evolution {@code duration} is
151      *         {@code null}
152      */
153     public static Predicate<Object>
154     byExecutionTime(final Duration duration) {
155         return byExecutionTime(duration, NanoClock.systemUTC());
156     }
157 
158     /**
159      * Return a predicate, which will truncated the evolution stream if the
160      * best fitness of the current population becomes less than the specified
161      * threshold and the objective is set to minimize the fitness. This
162      * predicate also stops the evolution if the best fitness in the current
163      * population becomes greater than the user-specified fitness threshold when
164      * the objective is to maximize the fitness.
165      *
166      <pre>{@code
167      * final Phenotype<DoubleGene, Double> result = engine.stream()
168      *      // Truncate the evolution stream if the best fitness is higher than
169      *      // the given threshold of '2.3'.
170      *     .limit(byFitnessThreshold(2.3))
171      *      // The evolution will stop after maximal 250 generations; guarantees
172      *      // the termination (truncation) of the evolution stream.
173      *     .limit(250)
174      *     .collect(toBestPhenotype());
175      * }</pre>
176      *
177      @since 3.1
178      *
179      @param threshold the desired threshold
180      @param <C> the fitness type
181      @return the predicate which truncates the evolution stream based on the
182      *         given {@code threshold}.
183      @throws NullPointerException if the given {@code threshold} is
184      *        {@code null}.
185      */
186     public static <C extends Comparable<? super C>>
187     Predicate<EvolutionResult<?, C>> byFitnessThreshold(final C threshold) {
188         return new FitnessThresholdLimit<>(threshold);
189     }
190 
191 
192 }