001 /*
002 * Java Genetic Algorithm Library (jenetics-3.9.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@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 }
|