AnyChromosome.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-7.0.0).
003  * Copyright (c) 2007-2022 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  <pre>{@code
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  * }</pre>
074  *
075  * The <i>full</i> example above shows how the {@code AnyChromosome} is used
076  * to use 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. An 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 }