AnyChromosome.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.7.0).
003  * Copyright (c) 2007-2016 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@gmx.at)
019  */
020 package org.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 org.jenetics.internal.util.Equality;
028 
029 import org.jenetics.util.ISeq;
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  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
079  @version 3.3
080  @since 3.3
081  */
082 public class AnyChromosome<A> extends AbstractChromosome<AnyGene<A>> {
083 
084     private final Supplier<? extends A> _supplier;
085     private final Predicate<? super A> _alleleValidator;
086     private final Predicate<? super ISeq<? super A>> _alleleSeqValidator;
087 
088     private Boolean _valid = null;
089 
090     /**
091      * Create a new {@code AnyChromosome} from the given {@code genes}
092      * array. An chromosome is valid if both, the {@code alleleValidator} and
093      * the {@code alleleSeqValidator} return {@code true}.
094      *
095      @param genes the genes that form the chromosome.
096      @param supplier the allele-supplier which is used for creating new,
097      *        random alleles
098      @param alleleValidator the validator used for validating the created gene.
099      *        This predicate is used in the {@link AnyGene#isValid()} method.
100      @param alleleSeqValidator the validator used for validating the created
101      *        chromosome. This predicate is used in the
102      *        {@link AnyChromosome#isValid()} method.
103      @throws NullPointerException if the given arguments is {@code null}
104      @throws IllegalArgumentException if the length of the gene array is
105      *         smaller than one.
106      */
107     protected AnyChromosome(
108         final ISeq<AnyGene<A>> genes,
109         final Supplier<? extends A> supplier,
110         final Predicate<? super A> alleleValidator,
111         final Predicate<? super ISeq<? super A>> alleleSeqValidator
112     ) {
113         super(genes);
114         _supplier = requireNonNull(supplier);
115         _alleleValidator = requireNonNull(alleleValidator);
116         _alleleSeqValidator = requireNonNull(alleleSeqValidator);
117     }
118 
119     @Override
120     public boolean isValid() {
121         Boolean valid =
122             (_alleleValidator == Equality.TRUE &&
123                 _alleleSeqValidator == Equality.TRUE)
124             ? Boolean.TRUE
125             : _valid;
126 
127         if (valid == null) {
128             final ISeq<A> alleles = toSeq().map(Gene::getAllele);
129             valid = _alleleSeqValidator.test(alleles&&
130                 alleles.forAll(_alleleValidator);
131         }
132 
133         return _valid = valid;
134     }
135 
136     @Override
137     public Chromosome<AnyGene<A>> newInstance(final ISeq<AnyGene<A>> genes) {
138         return new AnyChromosome<>(
139             genes,
140             _supplier,
141             _alleleValidator,
142             _alleleSeqValidator
143         );
144     }
145 
146     @Override
147     public Chromosome<AnyGene<A>> newInstance() {
148         return of(_supplier, _alleleValidator, _alleleSeqValidator, length());
149     }
150 
151 
152     /* *************************************************************************
153      *  Static factory methods.
154      * ************************************************************************/
155 
156     /**
157      * Create a new chromosome of type {@code A} with the given parameters.
158      *
159      @param <A> the allele type
160      @param supplier the allele-supplier which is used for creating new,
161      *        random alleles
162      @param alleleValidator the validator used for validating the created gene.
163      *        This predicate is used in the {@link AnyGene#isValid()} method.
164      @param alleleSeqValidator the validator used for validating the created
165      *        chromosome. This predicate is used in the
166      *        {@link AnyChromosome#isValid()} method.
167      @param length the length of the created chromosome
168      @return a new chromosome of allele type {@code A}
169      @throws NullPointerException if the given arguments is {@code null}
170      @throws IllegalArgumentException if chromosome length is smaller than one.
171      */
172     public static <A> AnyChromosome<A> of(
173         final Supplier<? extends A> supplier,
174         final Predicate<? super A> alleleValidator,
175         final Predicate<? super ISeq<? super A>> alleleSeqValidator,
176         final int length
177     ) {
178         return new AnyChromosome<>(
179             AnyGene.seq(length, supplier, alleleValidator),
180             supplier,
181             alleleValidator,
182             alleleSeqValidator
183         );
184     }
185 
186     /**
187      * Create a new chromosome of type {@code A} with the given parameters.
188      *
189      @param <A> the allele type
190      @param supplier the allele-supplier which is used for creating new,
191      *        random alleles
192      @param validator the validator used for validating the created gene. This
193      *        predicate is used in the {@link AnyGene#isValid()} method.
194      @param length the length of the created chromosome
195      @return a new chromosome of allele type {@code A}
196      @throws NullPointerException if the {@code supplier} or {@code validator}
197      *         is {@code null}
198      @throws IllegalArgumentException if chromosome length is smaller than one.
199      */
200     public static <A> AnyChromosome<A> of(
201         final Supplier<? extends A> supplier,
202         final Predicate<? super A> validator,
203         final int length
204     ) {
205         return of(supplier, validator, Equality.TRUE, length);
206     }
207 
208     /**
209      * Create a new chromosome of type {@code A} with the given parameters and
210      * length one.
211      *
212      @param <A> the allele type
213      @param supplier the allele-supplier which is used for creating new,
214      *        random alleles
215      @param validator the validator used for validating the created gene. This
216      *        predicate is used in the {@link #isValid()} method.
217      @return a new chromosome of allele type {@code A}
218      @throws NullPointerException if the {@code supplier} or {@code validator}
219      *         is {@code null}
220      */
221     public static <A> AnyChromosome<A> of(
222         final Supplier<? extends A> supplier,
223         final Predicate<? super A> validator
224     ) {
225         return of(supplier, validator, 1);
226     }
227 
228     /**
229      * Create a new chromosome of type {@code A} with the given parameters. The
230      * {@code validator} predicate of the generated gene will always return
231      * {@code true}.
232      *
233      @param <A> the allele type
234      @param supplier the allele-supplier which is used for creating new,
235      *        random alleles
236      @param length the length of the created chromosome
237      @return a new chromosome of allele type {@code A}
238      @throws NullPointerException if the {@code supplier} is {@code null}
239      @throws IllegalArgumentException if chromosome length is smaller than one.
240      */
241     public static <A> AnyChromosome<A> of(
242         final Supplier<? extends A> supplier,
243         final int length
244     ) {
245         return of(supplier, Equality.TRUE, length);
246     }
247 
248     /**
249      * Create a new chromosome of type {@code A} with the given parameters and
250      * length one. The {@code validator} predicate of the generated gene will
251      * always return {@code true}.
252      *
253      @param <A> the allele type
254      @param supplier the allele-supplier which is used for creating new,
255      *        random alleles
256      @return a new chromosome of allele type {@code A}
257      @throws NullPointerException if the {@code supplier} is {@code null}
258      */
259     public static <A> AnyChromosome<A> of(final Supplier<? extends A> supplier) {
260         return of(supplier, 1);
261     }
262 
263 }