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