001 /*
002 * Java Genetic Algorithm Library (jenetics-6.1.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 ([email protected])
019 */
020 package io.jenetics.engine;
021
022 import static java.util.Objects.requireNonNull;
023
024 import java.util.function.Predicate;
025
026 import io.jenetics.Gene;
027 import io.jenetics.Genotype;
028 import io.jenetics.Phenotype;
029 import io.jenetics.util.Factory;
030
031 /**
032 * This simple {@code Constraint} implementation <em>repairs</em> an invalid
033 * phenotype by creating new individuals until a valid one has been created.
034 * If the probability of creating invalid individuals isn't to high, this is the
035 * preferred constraint implementation. E.g. if the probability of creating an
036 * invalid individual is 0.1, then the probability of creating an invalid
037 * phenotype after <em>n</em> retries, is 0.1<sup>n</sup>.
038 * <p>
039 * The following example constraint checks a 2-dimensional point for validity.
040 * In this example, a point is considered as valid, if it lies within the unit
041 * circle.
042 * <pre>{@code
043 * InvertibleCodec<double[], DoubleGene> codec = Codecs.ofVector(DoubleRange.of(-1, 1), 2);
044 * Constraint<DoubleGene, Double> constraint = RetryConstraint.of(
045 * codec,
046 * p -> p[0]*p[0] + p[1]*p[1] <= 1
047 * );
048 * }</pre>
049 * The probability that a randomly created point lies outside the unit circle is
050 * <em>1 - π/4 ≈ 0.2146</em>. This leads to a failure probability after 10
051 * tries of <em>0.2146<sup>10</sup> ≈ 0.000000207173567</em>. Since we are
052 * using an {@link InvertibleCodec}, it is much easier to implement our
053 * constraint. Otherwise we would need to check the validity on the
054 * {@link Phenotype} directly
055 *
056 * @apiNote
057 * This class is part of the more advanced API and is not needed for default use
058 * cases.
059 *
060 * @author <a href="mailto:[email protected]">Franz Wilhelmstötter</a>
061 * @version 5.2
062 * @since 5.0
063 */
064 public final class RetryConstraint<
065 G extends Gene<?, G>,
066 C extends Comparable<? super C>
067 >
068 implements Constraint<G, C>
069 {
070
071 /**
072 * The default retry-count for creating new, valid phenotypes.
073 */
074 public static final int DEFAULT_RETRY_COUNT = 10;
075
076 private final Predicate<? super Phenotype<G, C>> _validator;
077 private final Factory<Genotype<G>> _genotypeFactory;
078 private final int _retryLimit;
079
080 /**
081 * Create a new retry-constraint with the given parameters.
082 *
083 * @param validator the phenotype validator
084 * @param genotypeFactory the genotype factory used for creating new
085 * phenotypes. The genotype factory may be {@code null}. In this case,
086 * the phenotype to be repaired is used as template.
087 * @param retryLimit the limit of the phenotype creation retries. If more
088 * re-creation tries are necessary, an invalid phenotype is returned.
089 * This limit guarantees the termination of the
090 * {@link #repair(Phenotype,long)} method.
091 * @throws NullPointerException if the {@code validator} is {@code null}
092 */
093 public RetryConstraint(
094 final Predicate<? super Phenotype<G, C>> validator,
095 final Factory<Genotype<G>> genotypeFactory,
096 final int retryLimit
097 ) {
098 _validator = requireNonNull(validator);
099 _genotypeFactory = genotypeFactory;
100 _retryLimit = retryLimit;
101 }
102
103 @Override
104 public boolean test(final Phenotype<G, C> individual) {
105 return _validator.test(individual);
106 }
107
108 @Override
109 public Phenotype<G, C> repair(
110 final Phenotype<G, C> individual,
111 final long generation
112 ) {
113 final Factory<Genotype<G>> gtf = _genotypeFactory != null
114 ? _genotypeFactory
115 : individual.genotype();
116
117 int count = 0;
118 Phenotype<G, C> phenotype;
119 do {
120 phenotype = Phenotype.of(gtf.newInstance(), generation);
121 } while (++count < _retryLimit && !test(phenotype));
122
123 return phenotype;
124 }
125
126 /**
127 * Return a new constraint with the given genotype factory. The phenotype
128 * validator is set to {@link Phenotype#isValid()} and the retry count to
129 * {@link #DEFAULT_RETRY_COUNT}.
130 *
131 * @param genotypeFactory the genotype factory used for creating new
132 * phenotypes
133 * @param <G> the gene type
134 * @param <C> the fitness value type
135 * @return a new constraint strategy
136 */
137 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
138 RetryConstraint<G, C> of(final Factory<Genotype<G>> genotypeFactory) {
139 return new RetryConstraint<>(
140 Phenotype::isValid,
141 genotypeFactory,
142 DEFAULT_RETRY_COUNT
143 );
144 }
145
146 /**
147 * Return a new constraint with the given {@code validator} and the
148 * {@link #DEFAULT_RETRY_COUNT}.
149 *
150 * @param validator the phenotype validator
151 * @param <G> the gene type
152 * @param <C> the fitness value type
153 * @return a new constraint strategy
154 * @throws NullPointerException if the {@code validator} is {@code null}
155 */
156 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
157 RetryConstraint<G, C> of(final Predicate<? super Phenotype<G, C>> validator) {
158 return new RetryConstraint<>(
159 validator,
160 null,
161 DEFAULT_RETRY_COUNT
162 );
163 }
164
165 /**
166 * Return a new constraint with the given {@code validator} and the
167 * {@link #DEFAULT_RETRY_COUNT}.
168 *
169 * @since 5.2
170 *
171 * @param codec the invertible codec used for simplify the needed
172 * validator
173 * @param validator the phenotype validator
174 * @param <T> the type of the <em>native</em> problem domain
175 * @param <G> the gene type
176 * @param <C> the fitness value type
177 * @return a new constraint strategy
178 * @throws NullPointerException if the {@code codec} or {@code validator} is
179 * {@code null}
180 */
181 public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
182 Constraint<G, C> of(
183 final InvertibleCodec<T, G> codec,
184 final Predicate<? super T> validator
185 ) {
186 return of(pt -> validator.test(codec.decode(pt.genotype())));
187 }
188
189 /**
190 * Return a new constraint with the given {@code validator} and
191 * {@code retryLimit}.
192 *
193 * @param validator the phenotype validator
194 * @param retryLimit the limit of the phenotype creation retries. If more
195 * re-creation tries are necessary, an invalid phenotype is returned.
196 * This limit guarantees the termination of the
197 * {@link #repair(Phenotype, long)} method.
198 * @param <G> the gene type
199 * @param <C> the fitness value type
200 * @return a new constraint strategy
201 */
202 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
203 RetryConstraint<G, C> of(
204 final Predicate<? super Phenotype<G, C>> validator,
205 final int retryLimit
206 ) {
207 return new RetryConstraint<>(
208 validator,
209 null,
210 retryLimit
211 );
212 }
213
214 /**
215 * Return a new constraint with the given {@code validator} and
216 * {@code retryLimit}.
217 *
218 * @since 5.2
219 *
220 * @param codec the invertible codec used for simplify the needed
221 * validator
222 * @param validator the phenotype validator
223 * @param retryLimit the limit of the phenotype creation retries. If more
224 * re-creation tries are necessary, an invalid phenotype is returned.
225 * This limit guarantees the termination of the
226 * {@link #repair(Phenotype, long)} method.
227 * @param <T> the type of the <em>native</em> problem domain
228 * @param <G> the gene type
229 * @param <C> the fitness value type
230 * @return a new constraint strategy
231 * @throws NullPointerException if the {@code codec} or {@code validator} is
232 * {@code null}
233 */
234 public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
235 Constraint<G, C> of(
236 final InvertibleCodec<T, G> codec,
237 final Predicate<? super T> validator,
238 final int retryLimit
239 ) {
240 return of(
241 pt -> validator.test(codec.decode(pt.genotype())),
242 retryLimit
243 );
244 }
245
246 }
|