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