001/*
002 * Java Genetic Algorithm Library (jenetics-8.1.0).
003 * Copyright (c) 2007-2024 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 */
020package io.jenetics;
021
022import static java.util.Objects.requireNonNull;
023
024import java.util.function.Predicate;
025import java.util.function.Supplier;
026
027import io.jenetics.internal.util.Predicates;
028import io.jenetics.util.ISeq;
029import io.jenetics.util.IntRange;
030
031/**
032 * {@code Chromosome} implementation, which allows creating genes without
033 * explicit implementing the {@code Chromosome} interface.
034 *
035 * {@snippet lang="java":
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.gene().allele()
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 * }
074 *
075 * The <i>full</i> example above shows how the {@code AnyChromosome} is used
076 * to use it 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 5.2
085 * @since 3.3
086 */
087public 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. A 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 == Predicates.TRUE &&
132                                _alleleSeqValidator == Predicates.<ISeq<A>>True())
133                        ? Boolean.TRUE
134                        : _valid;
135
136                if (valid == null) {
137                        final ISeq<A> alleles = stream()
138                                .map(Gene::allele)
139                                .collect(ISeq.toISeq());
140
141                        valid = _alleleSeqValidator.test(alleles) &&
142                                alleles.forAll(_alleleValidator);
143                }
144
145                return _valid = valid;
146        }
147
148        @Override
149        public Chromosome<AnyGene<A>> newInstance(final ISeq<AnyGene<A>> genes) {
150                return new AnyChromosome<>(
151                        genes,
152                        _supplier,
153                        _alleleValidator,
154                        _alleleSeqValidator,
155                        lengthRange()
156                );
157        }
158
159        @Override
160        public Chromosome<AnyGene<A>> newInstance() {
161                return of(_supplier, _alleleValidator, _alleleSeqValidator, lengthRange());
162        }
163
164
165        /* *************************************************************************
166         *  Static factory methods.
167         * ************************************************************************/
168
169        /**
170         * Create a new chromosome of type {@code A} with the given parameters.
171         *
172         * @since 4.0
173         *
174         * @param <A> the allele type
175         * @param supplier the allele-supplier which is used for creating new,
176         *        random alleles
177         * @param alleleValidator the validator used for validating the created gene.
178         *        This predicate is used in the {@link AnyGene#isValid()} method.
179         * @param alleleSeqValidator the validator used for validating the created
180         *        chromosome. This predicate is used in the
181         *        {@link AnyChromosome#isValid()} method.
182         * @param lengthRange the allowed length range of the chromosome
183         * @return a new chromosome of allele type {@code A}
184         * @throws NullPointerException if the given arguments is {@code null}
185         * @throws IllegalArgumentException if chromosome length is smaller than one.
186         */
187        public static <A> AnyChromosome<A> of(
188                final Supplier<? extends A> supplier,
189                final Predicate<? super A> alleleValidator,
190                final Predicate<? super ISeq<A>> alleleSeqValidator,
191                final IntRange lengthRange
192        ) {
193                return new AnyChromosome<>(
194                        AnyGene.seq(lengthRange, supplier, alleleValidator),
195                        supplier,
196                        alleleValidator,
197                        alleleSeqValidator,
198                        lengthRange
199                );
200        }
201
202        /**
203         * Create a new chromosome of type {@code A} with the given parameters.
204         *
205         * @param <A> the allele type
206         * @param supplier the allele-supplier which is used for creating new,
207         *        random alleles
208         * @param alleleValidator the validator used for validating the created gene.
209         *        This predicate is used in the {@link AnyGene#isValid()} method.
210         * @param alleleSeqValidator the validator used for validating the created
211         *        chromosome. This predicate is used in the
212         *        {@link AnyChromosome#isValid()} method.
213         * @param length the length of the chromosome
214         * @return a new chromosome of allele type {@code A}
215         * @throws NullPointerException if the given arguments is {@code null}
216         * @throws IllegalArgumentException if chromosome length is smaller than one.
217         */
218        public static <A> AnyChromosome<A> of(
219                final Supplier<? extends A> supplier,
220                final Predicate<? super A> alleleValidator,
221                final Predicate<? super ISeq<A>> alleleSeqValidator,
222                final int length
223        ) {
224                return of(supplier, alleleValidator, alleleSeqValidator, IntRange.of(length));
225        }
226
227        /**
228         * Create a new chromosome of type {@code A} with the given parameters.
229         *
230         * @since 4.0
231         *
232         * @param <A> the allele type
233         * @param supplier the allele-supplier which is used for creating new,
234         *        random alleles
235         * @param validator the validator used for validating the created gene. This
236         *        predicate is used in the {@link AnyGene#isValid()} method.
237         * @param lengthRange the allowed length range of the chromosome
238         * @return a new chromosome of allele type {@code A}
239         * @throws NullPointerException if the {@code supplier} or {@code validator}
240         *         is {@code null}
241         * @throws IllegalArgumentException if chromosome length is smaller than one.
242         */
243        public static <A> AnyChromosome<A> of(
244                final Supplier<? extends A> supplier,
245                final Predicate<? super A> validator,
246                final IntRange lengthRange
247        ) {
248                return of(supplier, validator, Predicates.True(), lengthRange);
249        }
250
251        /**
252         * Create a new chromosome of type {@code A} with the given parameters.
253         *
254         * @param <A> the allele type
255         * @param supplier the allele-supplier which is used for creating new,
256         *        random alleles
257         * @param validator the validator used for validating the created gene. This
258         *        predicate is used in the {@link AnyGene#isValid()} method.
259         * @param length the length of the chromosome
260         * @return a new chromosome of allele type {@code A}
261         * @throws NullPointerException if the {@code supplier} or {@code validator}
262         *         is {@code null}
263         * @throws IllegalArgumentException if chromosome length is smaller than one.
264         */
265        public static <A> AnyChromosome<A> of(
266                final Supplier<? extends A> supplier,
267                final Predicate<? super A> validator,
268                final int length
269        ) {
270                return of(supplier, validator, Predicates.True(), length);
271        }
272
273        /**
274         * Create a new chromosome of type {@code A} with the given parameters and
275         * length one.
276         *
277         * @param <A> the allele type
278         * @param supplier the allele-supplier which is used for creating new,
279         *        random alleles
280         * @param validator the validator used for validating the created gene. This
281         *        predicate is used in the {@link #isValid()} method.
282         * @return a new chromosome of allele type {@code A}
283         * @throws NullPointerException if the {@code supplier} or {@code validator}
284         *         is {@code null}
285         */
286        public static <A> AnyChromosome<A> of(
287                final Supplier<? extends A> supplier,
288                final Predicate<? super A> validator
289        ) {
290                return of(supplier, validator, 1);
291        }
292
293        /**
294         * Create a new chromosome of type {@code A} with the given parameters. The
295         * {@code validator} predicate of the generated gene will always return
296         * {@code true}.
297         *
298         * @since 4.0
299         *
300         * @param <A> the allele type
301         * @param supplier the allele-supplier which is used for creating new,
302         *        random alleles
303         * @param lengthRange the allowed length range of the chromosome
304         * @return a new chromosome of allele type {@code A}
305         * @throws NullPointerException if the {@code supplier} is {@code null}
306         * @throws IllegalArgumentException if chromosome length is smaller than one.
307         */
308        public static <A> AnyChromosome<A> of(
309                final Supplier<? extends A> supplier,
310                final IntRange lengthRange
311        ) {
312                return of(supplier, Predicates.TRUE, lengthRange);
313        }
314
315        /**
316         * Create a new chromosome of type {@code A} with the given parameters. The
317         * {@code validator} predicate of the generated gene will always return
318         * {@code true}.
319         *
320         * @param <A> the allele type
321         * @param supplier the allele-supplier which is used for creating new,
322         *        random alleles
323         * @param length the length of the created chromosome
324         * @return a new chromosome of allele type {@code A}
325         * @throws NullPointerException if the {@code supplier} is {@code null}
326         * @throws IllegalArgumentException if chromosome length is smaller than one.
327         */
328        public static <A> AnyChromosome<A> of(
329                final Supplier<? extends A> supplier,
330                final int length
331        ) {
332                return of(supplier, Predicates.TRUE, length);
333        }
334
335        /**
336         * Create a new chromosome of type {@code A} with the given parameters and
337         * length one. The {@code validator} predicate of the generated gene will
338         * always return {@code true}.
339         *
340         * @param <A> the allele type
341         * @param supplier the allele-supplier which is used for creating new,
342         *        random alleles
343         * @return a new chromosome of allele type {@code A}
344         * @throws NullPointerException if the {@code supplier} is {@code null}
345         */
346        public static <A> AnyChromosome<A> of(final Supplier<? extends A> supplier) {
347                return of(supplier, 1);
348        }
349
350}