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