001/*
002 * Java Genetic Algorithm Library (jenetics-8.3.0).
003 * Copyright (c) 2007-2025 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 * {@snippet lang="java":
035 * public class LastMonday {
036 *
037 *     // First Monday of 2015.
038 *     private static final LocalDate MIN_MONDAY = LocalDate.of(2015, 1, 5);
039 *
040 *     // The used Codec.
041 *     private static final Codec<LocalDate, AnyGene<LocalDate>> CODEC = Codec.of(
042 *         Genotype.of(AnyChromosome.of(LastMonday::nextRandomMonday)),
043 *         gt -> gt.gene().allele()
044 *     );
045 *
046 *     // Supplier of random 'LocalDate' objects. The implementation is responsible
047 *     // for guaranteeing the desired allele restriction. In this case, we will
048 *     // generate only mondays.
049 *     private static LocalDate nextRandomMonday() {
050 *         return MIN_MONDAY.plusWeeks(RandomRegistry.getRandom().nextInt(1000));
051 *     }
052 *
053 *     // The fitness function: find a Monday at the end of the month.
054 *     private static double fitness(final LocalDate date) {
055 *         return date.getDayOfMonth();
056 *     }
057 *
058 *     public static void main(final String[] args) {
059 *         final Engine<AnyGene<LocalDate>, Double> engine = Engine
060 *             .builder(LastMonday::fitness, CODEC)
061 *             .offspringSelector(new RouletteWheelSelector<>())
062 *             .build();
063 *
064 *         final Phenotype<AnyGene<LocalDate>, Double> best = engine.stream()
065 *             .limit(50)
066 *             .collect(EvolutionResult.toBestPhenotype());
067 *
068 *         System.out.println(best);
069 *     }
070 *
071 * }
072 * }
073 *
074 * The <i>full</i> example above shows how the {@code AnyChromosome} is used
075 * to use it for an allele-type with no predefined gene- and chromosome type.
076 *
077 * @see AnyGene
078 *
079 * @implSpec
080 * This class is immutable and thread-safe.
081 *
082 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
083 * @version 5.2
084 * @since 3.3
085 */
086public class AnyChromosome<A> extends VariableChromosome<AnyGene<A>> {
087
088        private final Supplier<? extends A> _supplier;
089        private final Predicate<? super A> _alleleValidator;
090        private final Predicate<? super ISeq<A>> _alleleSeqValidator;
091
092        private Boolean _valid = null;
093
094        /**
095         * Create a new {@code AnyChromosome} from the given {@code genes}
096         * array. A chromosome is valid if both, the {@code alleleValidator} and
097         * the {@code alleleSeqValidator} return {@code true}.
098         *
099         * @param genes the genes that form the chromosome.
100         * @param lengthRange the allowed length range of the chromosome
101         * @param supplier the allele-supplier which is used for creating new,
102         *        random alleles
103         * @param alleleValidator the validator used for validating the created gene.
104         *        This predicate is used in the {@link AnyGene#isValid()} method.
105         * @param alleleSeqValidator the validator used for validating the created
106         *        chromosome. This predicate is used in the
107         *        {@link AnyChromosome#isValid()} method.
108         * @throws NullPointerException if the given arguments is {@code null}
109         * @throws IllegalArgumentException if the length of the gene sequence is
110         *         empty, doesn't match with the allowed length range, the minimum
111         *         or maximum of the range is smaller or equal zero, or the given
112         *         range size is zero.
113         */
114        protected AnyChromosome(
115                final ISeq<AnyGene<A>> genes,
116                final Supplier<? extends A> supplier,
117                final Predicate<? super A> alleleValidator,
118                final Predicate<? super ISeq<A>> alleleSeqValidator,
119                final IntRange lengthRange
120        ) {
121                super(genes, lengthRange);
122                _supplier = requireNonNull(supplier);
123                _alleleValidator = requireNonNull(alleleValidator);
124                _alleleSeqValidator = requireNonNull(alleleSeqValidator);
125        }
126
127        @Override
128        public boolean isValid() {
129                Boolean valid =
130                        (_alleleValidator == Predicates.TRUE &&
131                                _alleleSeqValidator == Predicates.<ISeq<A>>True())
132                        ? Boolean.TRUE
133                        : _valid;
134
135                if (valid == null) {
136                        final ISeq<A> alleles = stream()
137                                .map(Gene::allele)
138                                .collect(ISeq.toISeq());
139
140                        valid = _alleleSeqValidator.test(alleles) &&
141                                alleles.forAll(_alleleValidator);
142                }
143
144                return _valid = valid;
145        }
146
147        @Override
148        public Chromosome<AnyGene<A>> newInstance(final ISeq<AnyGene<A>> genes) {
149                return new AnyChromosome<>(
150                        genes,
151                        _supplier,
152                        _alleleValidator,
153                        _alleleSeqValidator,
154                        lengthRange()
155                );
156        }
157
158        @Override
159        public Chromosome<AnyGene<A>> newInstance() {
160                return of(_supplier, _alleleValidator, _alleleSeqValidator, lengthRange());
161        }
162
163
164        /* *************************************************************************
165         *  Static factory methods.
166         * ************************************************************************/
167
168        /**
169         * Create a new chromosome of type {@code A} with the given parameters.
170         *
171         * @since 4.0
172         *
173         * @param <A> the allele type
174         * @param supplier the allele-supplier which is used for creating new,
175         *        random alleles
176         * @param alleleValidator the validator used for validating the created gene.
177         *        This predicate is used in the {@link AnyGene#isValid()} method.
178         * @param alleleSeqValidator the validator used for validating the created
179         *        chromosome. This predicate is used in the
180         *        {@link AnyChromosome#isValid()} method.
181         * @param lengthRange the allowed length range of the chromosome
182         * @return a new chromosome of allele type {@code A}
183         * @throws NullPointerException if the given arguments is {@code null}
184         * @throws IllegalArgumentException if the chromosome length is smaller than
185         *         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 the chromosome length is smaller than
217         *         one.
218         */
219        public static <A> AnyChromosome<A> of(
220                final Supplier<? extends A> supplier,
221                final Predicate<? super A> alleleValidator,
222                final Predicate<? super ISeq<A>> alleleSeqValidator,
223                final int length
224        ) {
225                return of(supplier, alleleValidator, alleleSeqValidator, new IntRange(length));
226        }
227
228        /**
229         * Create a new chromosome of type {@code A} with the given parameters.
230         *
231         * @since 4.0
232         *
233         * @param <A> the allele type
234         * @param supplier the allele-supplier which is used for creating new,
235         *        random alleles
236         * @param validator the validator used for validating the created gene. This
237         *        predicate is used in the {@link AnyGene#isValid()} method.
238         * @param lengthRange the allowed length range of the chromosome
239         * @return a new chromosome of allele type {@code A}
240         * @throws NullPointerException if the {@code supplier} or {@code validator}
241         *         is {@code null}
242         * @throws IllegalArgumentException if the chromosome length is smaller than
243         *         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.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 the chromosome length is smaller than
266         *         one.
267         */
268        public static <A> AnyChromosome<A> of(
269                final Supplier<? extends A> supplier,
270                final Predicate<? super A> validator,
271                final int length
272        ) {
273                return of(supplier, validator, Predicates.True(), length);
274        }
275
276        /**
277         * Create a new chromosome of type {@code A} with the given parameters and
278         * length one.
279         *
280         * @param <A> the allele type
281         * @param supplier the allele-supplier which is used for creating new,
282         *        random alleles
283         * @param validator the validator used for validating the created gene. This
284         *        predicate is used in the {@link #isValid()} method.
285         * @return a new chromosome of allele type {@code A}
286         * @throws NullPointerException if the {@code supplier} or {@code validator}
287         *         is {@code null}
288         */
289        public static <A> AnyChromosome<A> of(
290                final Supplier<? extends A> supplier,
291                final Predicate<? super A> validator
292        ) {
293                return of(supplier, validator, 1);
294        }
295
296        /**
297         * Create a new chromosome of type {@code A} with the given parameters. The
298         * {@code validator} predicate of the generated gene will always return
299         * {@code true}.
300         *
301         * @since 4.0
302         *
303         * @param <A> the allele type
304         * @param supplier the allele-supplier which is used for creating new,
305         *        random alleles
306         * @param lengthRange the allowed length range of the chromosome
307         * @return a new chromosome of allele type {@code A}
308         * @throws NullPointerException if the {@code supplier} is {@code null}
309         * @throws IllegalArgumentException if the chromosome length is smaller than
310         *         one
311         */
312        public static <A> AnyChromosome<A> of(
313                final Supplier<? extends A> supplier,
314                final IntRange lengthRange
315        ) {
316                return of(supplier, Predicates.TRUE, lengthRange);
317        }
318
319        /**
320         * Create a new chromosome of type {@code A} with the given parameters. The
321         * {@code validator} predicate of the generated gene will always return
322         * {@code true}.
323         *
324         * @param <A> the allele type
325         * @param supplier the allele-supplier which is used for creating new,
326         *        random alleles
327         * @param length the length of the created chromosome
328         * @return a new chromosome of allele type {@code A}
329         * @throws NullPointerException if the {@code supplier} is {@code null}
330         * @throws IllegalArgumentException if the chromosome length is smaller than
331         *         one
332         */
333        public static <A> AnyChromosome<A> of(
334                final Supplier<? extends A> supplier,
335                final int length
336        ) {
337                return of(supplier, Predicates.TRUE, length);
338        }
339
340        /**
341         * Create a new chromosome of type {@code A} with the given parameters and
342         * length one. The {@code validator} predicate of the generated gene will
343         * always return {@code true}.
344         *
345         * @param <A> the allele type
346         * @param supplier the allele-supplier which is used for creating new,
347         *        random alleles
348         * @return a new chromosome of allele type {@code A}
349         * @throws NullPointerException if the {@code supplier} is {@code null}
350         */
351        public static <A> AnyChromosome<A> of(final Supplier<? extends A> supplier) {
352                return of(supplier, 1);
353        }
354
355}