AnyChromosome.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-6.3.0).
003  * Copyright (c) 2007-2021 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 static final long serialVersionUID = 1L;
090 
091     private final Supplier<? extends A> _supplier;
092     private final Predicate<? super A> _alleleValidator;
093     private final Predicate<? super ISeq<A>> _alleleSeqValidator;
094 
095     private Boolean _valid = null;
096 
097     /**
098      * Create a new {@code AnyChromosome} from the given {@code genes}
099      * array. An chromosome is valid if both, the {@code alleleValidator} and
100      * the {@code alleleSeqValidator} return {@code true}.
101      *
102      @param genes the genes that form the chromosome.
103      @param lengthRange the allowed length range of the chromosome
104      @param supplier the allele-supplier which is used for creating new,
105      *        random alleles
106      @param alleleValidator the validator used for validating the created gene.
107      *        This predicate is used in the {@link AnyGene#isValid()} method.
108      @param alleleSeqValidator the validator used for validating the created
109      *        chromosome. This predicate is used in the
110      *        {@link AnyChromosome#isValid()} method.
111      @throws NullPointerException if the given arguments is {@code null}
112      @throws IllegalArgumentException if the length of the gene sequence is
113      *         empty, doesn't match with the allowed length range, the minimum
114      *         or maximum of the range is smaller or equal zero or the given
115      *         range size is zero.
116      */
117     protected AnyChromosome(
118         final ISeq<AnyGene<A>> genes,
119         final Supplier<? extends A> supplier,
120         final Predicate<? super A> alleleValidator,
121         final Predicate<? super ISeq<A>> alleleSeqValidator,
122         final IntRange lengthRange
123     ) {
124         super(genes, lengthRange);
125         _supplier = requireNonNull(supplier);
126         _alleleValidator = requireNonNull(alleleValidator);
127         _alleleSeqValidator = requireNonNull(alleleSeqValidator);
128     }
129 
130     @Override
131     public boolean isValid() {
132         Boolean valid =
133             (_alleleValidator == Predicates.TRUE &&
134                 _alleleSeqValidator == Predicates.<ISeq<A>>True())
135             ? Boolean.TRUE
136             : _valid;
137 
138         if (valid == null) {
139             final ISeq<A> alleles = stream()
140                 .map(Gene::allele)
141                 .collect(ISeq.toISeq());
142 
143             valid = _alleleSeqValidator.test(alleles&&
144                 alleles.forAll(_alleleValidator);
145         }
146 
147         return _valid = valid;
148     }
149 
150     @Override
151     public Chromosome<AnyGene<A>> newInstance(final ISeq<AnyGene<A>> genes) {
152         return new AnyChromosome<>(
153             genes,
154             _supplier,
155             _alleleValidator,
156             _alleleSeqValidator,
157             lengthRange()
158         );
159     }
160 
161     @Override
162     public Chromosome<AnyGene<A>> newInstance() {
163         return of(_supplier, _alleleValidator, _alleleSeqValidator, lengthRange());
164     }
165 
166 
167     /* *************************************************************************
168      *  Static factory methods.
169      * ************************************************************************/
170 
171     /**
172      * Create a new chromosome of type {@code A} with the given parameters.
173      *
174      @since 4.0
175      *
176      @param <A> the allele type
177      @param supplier the allele-supplier which is used for creating new,
178      *        random alleles
179      @param alleleValidator the validator used for validating the created gene.
180      *        This predicate is used in the {@link AnyGene#isValid()} method.
181      @param alleleSeqValidator the validator used for validating the created
182      *        chromosome. This predicate is used in the
183      *        {@link AnyChromosome#isValid()} method.
184      @param lengthRange the allowed length range of the chromosome
185      @return a new chromosome of allele type {@code A}
186      @throws NullPointerException if the given arguments is {@code null}
187      @throws IllegalArgumentException if chromosome length is smaller than one.
188      */
189     public static <A> AnyChromosome<A> of(
190         final Supplier<? extends A> supplier,
191         final Predicate<? super A> alleleValidator,
192         final Predicate<? super ISeq<A>> alleleSeqValidator,
193         final IntRange lengthRange
194     ) {
195         return new AnyChromosome<>(
196             AnyGene.seq(lengthRange, supplier, alleleValidator),
197             supplier,
198             alleleValidator,
199             alleleSeqValidator,
200             lengthRange
201         );
202     }
203 
204     /**
205      * Create a new chromosome of type {@code A} with the given parameters.
206      *
207      @param <A> the allele type
208      @param supplier the allele-supplier which is used for creating new,
209      *        random alleles
210      @param alleleValidator the validator used for validating the created gene.
211      *        This predicate is used in the {@link AnyGene#isValid()} method.
212      @param alleleSeqValidator the validator used for validating the created
213      *        chromosome. This predicate is used in the
214      *        {@link AnyChromosome#isValid()} method.
215      @param length the length of the chromosome
216      @return a new chromosome of allele type {@code A}
217      @throws NullPointerException if the given arguments is {@code null}
218      @throws IllegalArgumentException if chromosome length is smaller than one.
219      */
220     public static <A> AnyChromosome<A> of(
221         final Supplier<? extends A> supplier,
222         final Predicate<? super A> alleleValidator,
223         final Predicate<? super ISeq<A>> alleleSeqValidator,
224         final int length
225     ) {
226         return of(supplier, alleleValidator, alleleSeqValidator, IntRange.of(length));
227     }
228 
229     /**
230      * Create a new chromosome of type {@code A} with the given parameters.
231      *
232      @since 4.0
233      *
234      @param <A> the allele type
235      @param supplier the allele-supplier which is used for creating new,
236      *        random alleles
237      @param validator the validator used for validating the created gene. This
238      *        predicate is used in the {@link AnyGene#isValid()} method.
239      @param lengthRange the allowed length range of the chromosome
240      @return a new chromosome of allele type {@code A}
241      @throws NullPointerException if the {@code supplier} or {@code validator}
242      *         is {@code null}
243      @throws IllegalArgumentException if chromosome length is smaller than 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 chromosome length is smaller than one.
266      */
267     public static <A> AnyChromosome<A> of(
268         final Supplier<? extends A> supplier,
269         final Predicate<? super A> validator,
270         final int length
271     ) {
272         return of(supplier, validator, Predicates.True(), length);
273     }
274 
275     /**
276      * Create a new chromosome of type {@code A} with the given parameters and
277      * length one.
278      *
279      @param <A> the allele type
280      @param supplier the allele-supplier which is used for creating new,
281      *        random alleles
282      @param validator the validator used for validating the created gene. This
283      *        predicate is used in the {@link #isValid()} method.
284      @return a new chromosome of allele type {@code A}
285      @throws NullPointerException if the {@code supplier} or {@code validator}
286      *         is {@code null}
287      */
288     public static <A> AnyChromosome<A> of(
289         final Supplier<? extends A> supplier,
290         final Predicate<? super A> validator
291     ) {
292         return of(supplier, validator, 1);
293     }
294 
295     /**
296      * Create a new chromosome of type {@code A} with the given parameters. The
297      * {@code validator} predicate of the generated gene will always return
298      * {@code true}.
299      *
300      @since 4.0
301      *
302      @param <A> the allele type
303      @param supplier the allele-supplier which is used for creating new,
304      *        random alleles
305      @param lengthRange the allowed length range of the chromosome
306      @return a new chromosome of allele type {@code A}
307      @throws NullPointerException if the {@code supplier} is {@code null}
308      @throws IllegalArgumentException if chromosome length is smaller than one.
309      */
310     public static <A> AnyChromosome<A> of(
311         final Supplier<? extends A> supplier,
312         final IntRange lengthRange
313     ) {
314         return of(supplier, Predicates.TRUE, lengthRange);
315     }
316 
317     /**
318      * Create a new chromosome of type {@code A} with the given parameters. The
319      * {@code validator} predicate of the generated gene will always return
320      * {@code true}.
321      *
322      @param <A> the allele type
323      @param supplier the allele-supplier which is used for creating new,
324      *        random alleles
325      @param length the length of the created chromosome
326      @return a new chromosome of allele type {@code A}
327      @throws NullPointerException if the {@code supplier} is {@code null}
328      @throws IllegalArgumentException if chromosome length is smaller than one.
329      */
330     public static <A> AnyChromosome<A> of(
331         final Supplier<? extends A> supplier,
332         final int length
333     ) {
334         return of(supplier, Predicates.TRUE, length);
335     }
336 
337     /**
338      * Create a new chromosome of type {@code A} with the given parameters and
339      * length one. The {@code validator} predicate of the generated gene will
340      * always return {@code true}.
341      *
342      @param <A> the allele type
343      @param supplier the allele-supplier which is used for creating new,
344      *        random alleles
345      @return a new chromosome of allele type {@code A}
346      @throws NullPointerException if the {@code supplier} is {@code null}
347      */
348     public static <A> AnyChromosome<A> of(final Supplier<? extends A> supplier) {
349         return of(supplier, 1);
350     }
351 
352 }