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; 021 022import static java.util.Objects.requireNonNull; 023 024import java.util.function.Predicate; 025import java.util.function.Supplier; 026 027import io.jenetics.internal.util.Predicates; 028import io.jenetics.util.ISeq; 029import io.jenetics.util.IntRange; 030 031/** 032 * {@code Chromosome} implementation, which allows creating genes without 033 * explicit implementing the {@code Chromosome} interface. 034 * 035 * {@snippet lang="java": 036 * public class LastMonday { 037 * 038 * // First monday of 2015. 039 * private static final LocalDate MIN_MONDAY = LocalDate.of(2015, 1, 5); 040 * 041 * // The used Codec. 042 * private static final Codec<LocalDate, AnyGene<LocalDate>> CODEC = Codec.of( 043 * Genotype.of(AnyChromosome.of(LastMonday::nextRandomMonday)), 044 * gt -> gt.gene().allele() 045 * ); 046 * 047 * // Supplier of random 'LocalDate' objects. The implementation is responsible 048 * // for guaranteeing the desired allele restriction. In this case we will 049 * // generate only mondays. 050 * private static LocalDate nextRandomMonday() { 051 * return MIN_MONDAY.plusWeeks(RandomRegistry.getRandom().nextInt(1000)); 052 * } 053 * 054 * // The fitness function: find a monday at the end of the month. 055 * private static double fitness(final LocalDate date) { 056 * return date.getDayOfMonth(); 057 * } 058 * 059 * public static void main(final String[] args) { 060 * final Engine<AnyGene<LocalDate>, Double> engine = Engine 061 * .builder(LastMonday::fitness, CODEC) 062 * .offspringSelector(new RouletteWheelSelector<>()) 063 * .build(); 064 * 065 * final Phenotype<AnyGene<LocalDate>, Double> best = engine.stream() 066 * .limit(50) 067 * .collect(EvolutionResult.toBestPhenotype()); 068 * 069 * System.out.println(best); 070 * } 071 * 072 * } 073 * } 074 * 075 * The <i>full</i> example above shows how the {@code AnyChromosome} is used 076 * to use it for an allele-type with no predefined gene- and chromosome type. 077 * 078 * @see AnyGene 079 * 080 * @implSpec 081 * This class is immutable and thread-safe. 082 * 083 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 084 * @version 5.2 085 * @since 3.3 086 */ 087public class AnyChromosome<A> extends VariableChromosome<AnyGene<A>> { 088 089 private final Supplier<? extends A> _supplier; 090 private final Predicate<? super A> _alleleValidator; 091 private final Predicate<? super ISeq<A>> _alleleSeqValidator; 092 093 private Boolean _valid = null; 094 095 /** 096 * Create a new {@code AnyChromosome} from the given {@code genes} 097 * array. A chromosome is valid if both, the {@code alleleValidator} and 098 * the {@code alleleSeqValidator} return {@code true}. 099 * 100 * @param genes the genes that form the chromosome. 101 * @param lengthRange the allowed length range of the chromosome 102 * @param supplier the allele-supplier which is used for creating new, 103 * random alleles 104 * @param alleleValidator the validator used for validating the created gene. 105 * This predicate is used in the {@link AnyGene#isValid()} method. 106 * @param alleleSeqValidator the validator used for validating the created 107 * chromosome. This predicate is used in the 108 * {@link AnyChromosome#isValid()} method. 109 * @throws NullPointerException if the given arguments is {@code null} 110 * @throws IllegalArgumentException if the length of the gene sequence is 111 * empty, doesn't match with the allowed length range, the minimum 112 * or maximum of the range is smaller or equal zero, or the given 113 * range size is zero. 114 */ 115 protected AnyChromosome( 116 final ISeq<AnyGene<A>> genes, 117 final Supplier<? extends A> supplier, 118 final Predicate<? super A> alleleValidator, 119 final Predicate<? super ISeq<A>> alleleSeqValidator, 120 final IntRange lengthRange 121 ) { 122 super(genes, lengthRange); 123 _supplier = requireNonNull(supplier); 124 _alleleValidator = requireNonNull(alleleValidator); 125 _alleleSeqValidator = requireNonNull(alleleSeqValidator); 126 } 127 128 @Override 129 public boolean isValid() { 130 Boolean valid = 131 (_alleleValidator == Predicates.TRUE && 132 _alleleSeqValidator == Predicates.<ISeq<A>>True()) 133 ? Boolean.TRUE 134 : _valid; 135 136 if (valid == null) { 137 final ISeq<A> alleles = stream() 138 .map(Gene::allele) 139 .collect(ISeq.toISeq()); 140 141 valid = _alleleSeqValidator.test(alleles) && 142 alleles.forAll(_alleleValidator); 143 } 144 145 return _valid = valid; 146 } 147 148 @Override 149 public Chromosome<AnyGene<A>> newInstance(final ISeq<AnyGene<A>> genes) { 150 return new AnyChromosome<>( 151 genes, 152 _supplier, 153 _alleleValidator, 154 _alleleSeqValidator, 155 lengthRange() 156 ); 157 } 158 159 @Override 160 public Chromosome<AnyGene<A>> newInstance() { 161 return of(_supplier, _alleleValidator, _alleleSeqValidator, lengthRange()); 162 } 163 164 165 /* ************************************************************************* 166 * Static factory methods. 167 * ************************************************************************/ 168 169 /** 170 * Create a new chromosome of type {@code A} with the given parameters. 171 * 172 * @since 4.0 173 * 174 * @param <A> the allele type 175 * @param supplier the allele-supplier which is used for creating new, 176 * random alleles 177 * @param alleleValidator the validator used for validating the created gene. 178 * This predicate is used in the {@link AnyGene#isValid()} method. 179 * @param alleleSeqValidator the validator used for validating the created 180 * chromosome. This predicate is used in the 181 * {@link AnyChromosome#isValid()} method. 182 * @param lengthRange the allowed length range of the chromosome 183 * @return a new chromosome of allele type {@code A} 184 * @throws NullPointerException if the given arguments is {@code null} 185 * @throws IllegalArgumentException if chromosome length is smaller than one. 186 */ 187 public static <A> AnyChromosome<A> of( 188 final Supplier<? extends A> supplier, 189 final Predicate<? super A> alleleValidator, 190 final Predicate<? super ISeq<A>> alleleSeqValidator, 191 final IntRange lengthRange 192 ) { 193 return new AnyChromosome<>( 194 AnyGene.seq(lengthRange, supplier, alleleValidator), 195 supplier, 196 alleleValidator, 197 alleleSeqValidator, 198 lengthRange 199 ); 200 } 201 202 /** 203 * Create a new chromosome of type {@code A} with the given parameters. 204 * 205 * @param <A> the allele type 206 * @param supplier the allele-supplier which is used for creating new, 207 * random alleles 208 * @param alleleValidator the validator used for validating the created gene. 209 * This predicate is used in the {@link AnyGene#isValid()} method. 210 * @param alleleSeqValidator the validator used for validating the created 211 * chromosome. This predicate is used in the 212 * {@link AnyChromosome#isValid()} method. 213 * @param length the length of the chromosome 214 * @return a new chromosome of allele type {@code A} 215 * @throws NullPointerException if the given arguments is {@code null} 216 * @throws IllegalArgumentException if chromosome length is smaller than one. 217 */ 218 public static <A> AnyChromosome<A> of( 219 final Supplier<? extends A> supplier, 220 final Predicate<? super A> alleleValidator, 221 final Predicate<? super ISeq<A>> alleleSeqValidator, 222 final int length 223 ) { 224 return of(supplier, alleleValidator, alleleSeqValidator, IntRange.of(length)); 225 } 226 227 /** 228 * Create a new chromosome of type {@code A} with the given parameters. 229 * 230 * @since 4.0 231 * 232 * @param <A> the allele type 233 * @param supplier the allele-supplier which is used for creating new, 234 * random alleles 235 * @param validator the validator used for validating the created gene. This 236 * predicate is used in the {@link AnyGene#isValid()} method. 237 * @param lengthRange the allowed length range of the chromosome 238 * @return a new chromosome of allele type {@code A} 239 * @throws NullPointerException if the {@code supplier} or {@code validator} 240 * is {@code null} 241 * @throws IllegalArgumentException if chromosome length is smaller than one. 242 */ 243 public static <A> AnyChromosome<A> of( 244 final Supplier<? extends A> supplier, 245 final Predicate<? super A> validator, 246 final IntRange lengthRange 247 ) { 248 return of(supplier, validator, Predicates.True(), lengthRange); 249 } 250 251 /** 252 * Create a new chromosome of type {@code A} with the given parameters. 253 * 254 * @param <A> the allele type 255 * @param supplier the allele-supplier which is used for creating new, 256 * random alleles 257 * @param validator the validator used for validating the created gene. This 258 * predicate is used in the {@link AnyGene#isValid()} method. 259 * @param length the length of the chromosome 260 * @return a new chromosome of allele type {@code A} 261 * @throws NullPointerException if the {@code supplier} or {@code validator} 262 * is {@code null} 263 * @throws IllegalArgumentException if chromosome length is smaller than one. 264 */ 265 public static <A> AnyChromosome<A> of( 266 final Supplier<? extends A> supplier, 267 final Predicate<? super A> validator, 268 final int length 269 ) { 270 return of(supplier, validator, Predicates.True(), length); 271 } 272 273 /** 274 * Create a new chromosome of type {@code A} with the given parameters and 275 * length one. 276 * 277 * @param <A> the allele type 278 * @param supplier the allele-supplier which is used for creating new, 279 * random alleles 280 * @param validator the validator used for validating the created gene. This 281 * predicate is used in the {@link #isValid()} method. 282 * @return a new chromosome of allele type {@code A} 283 * @throws NullPointerException if the {@code supplier} or {@code validator} 284 * is {@code null} 285 */ 286 public static <A> AnyChromosome<A> of( 287 final Supplier<? extends A> supplier, 288 final Predicate<? super A> validator 289 ) { 290 return of(supplier, validator, 1); 291 } 292 293 /** 294 * Create a new chromosome of type {@code A} with the given parameters. The 295 * {@code validator} predicate of the generated gene will always return 296 * {@code true}. 297 * 298 * @since 4.0 299 * 300 * @param <A> the allele type 301 * @param supplier the allele-supplier which is used for creating new, 302 * random alleles 303 * @param lengthRange the allowed length range of the chromosome 304 * @return a new chromosome of allele type {@code A} 305 * @throws NullPointerException if the {@code supplier} is {@code null} 306 * @throws IllegalArgumentException if chromosome length is smaller than one. 307 */ 308 public static <A> AnyChromosome<A> of( 309 final Supplier<? extends A> supplier, 310 final IntRange lengthRange 311 ) { 312 return of(supplier, Predicates.TRUE, lengthRange); 313 } 314 315 /** 316 * Create a new chromosome of type {@code A} with the given parameters. The 317 * {@code validator} predicate of the generated gene will always return 318 * {@code true}. 319 * 320 * @param <A> the allele type 321 * @param supplier the allele-supplier which is used for creating new, 322 * random alleles 323 * @param length the length of the created chromosome 324 * @return a new chromosome of allele type {@code A} 325 * @throws NullPointerException if the {@code supplier} is {@code null} 326 * @throws IllegalArgumentException if chromosome length is smaller than one. 327 */ 328 public static <A> AnyChromosome<A> of( 329 final Supplier<? extends A> supplier, 330 final int length 331 ) { 332 return of(supplier, Predicates.TRUE, length); 333 } 334 335 /** 336 * Create a new chromosome of type {@code A} with the given parameters and 337 * length one. The {@code validator} predicate of the generated gene will 338 * always return {@code true}. 339 * 340 * @param <A> the allele type 341 * @param supplier the allele-supplier which is used for creating new, 342 * random alleles 343 * @return a new chromosome of allele type {@code A} 344 * @throws NullPointerException if the {@code supplier} is {@code null} 345 */ 346 public static <A> AnyChromosome<A> of(final Supplier<? extends A> supplier) { 347 return of(supplier, 1); 348 } 349 350}