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 }
|