001 /*
002 * Java Genetic Algorithm Library (jenetics-8.0.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 */
020 package io.jenetics;
021
022 import static java.util.Objects.requireNonNull;
023
024 import java.util.function.Predicate;
025 import java.util.function.Supplier;
026
027 import io.jenetics.internal.util.Predicates;
028 import io.jenetics.util.ISeq;
029 import io.jenetics.util.IntRange;
030
031 /**
032 * {@code Chromosome} implementation, which allows to create 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 */
087 public 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 }
|