001/* 002 * Java Genetic Algorithm Library (jenetics-8.1.0). 003 * Copyright (c) 2007-2024 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 */ 020package io.jenetics.engine; 021 022import static java.util.Objects.requireNonNull; 023 024import java.util.function.Predicate; 025 026import io.jenetics.Gene; 027import io.jenetics.Genotype; 028import io.jenetics.Phenotype; 029import 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 * {@snippet lang="java": 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 * } 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 unnecessary for default use 058 * cases. 059 * 060 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 061 * @version 5.2 062 * @since 5.0 063 */ 064public 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 a 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 counts 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 necessary 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 necessary 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}