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