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;
023import static io.jenetics.internal.util.Hashes.hash;
024import static io.jenetics.util.RandomRegistry.random;
025
026import java.util.Objects;
027import java.util.function.Predicate;
028import java.util.function.Supplier;
029
030import io.jenetics.util.ISeq;
031import io.jenetics.util.IntRange;
032import io.jenetics.util.MSeq;
033
034/**
035 * {@code Gene} implementation, which allows creating genes without explicit
036 * implementing the {@code Gene} interface.
037 *
038 * {@snippet lang="java":
039 * class Main {
040 *     // First monday of 2015.
041 *     private static final LocalDate MIN_MONDAY = LocalDate.of(2015, 1, 5);
042 *
043 *     // Supplier of random 'LocalDate' objects. The implementation is responsible
044 *     // for guaranteeing the desired allele restriction. In this case, we will
045 *     // generate only mondays.
046 *     static LocalDate nextRandomMonday() {
047 *         return MIN_MONDAY.plusWeeks(RandomRegistry.getRandom().nextInt(1000));
048 *     }
049 *
050 *     // Create a new 'LocalDate' gene. All other genes, created with
051 *     // gene.newInstance(), are calling the 'newRandomMonday' method.
052 *     final AnyGene<LocalDate> gene = AnyGene.of(Main::nextRandomMonday);
053 * }
054 * }
055 * The example above shows how to create {@code LocalDate} genes from a random
056 * {@code LocalDate} supplier. It also shows how to implement a restriction on
057 * the created dates. The usage of the {@code AnyGene} class is useful for
058 * supporting custom allele types without explicit implementation of the
059 * {@code Gene} interface. But the {@code AnyGene} can only be used for a subset
060 * of the existing alterers.
061 *
062 * @see AnyChromosome
063 *
064 * @implNote
065 * This class is immutable and thread-safe.
066 *
067 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
068 * @version 6.0
069 * @since 3.3
070 */
071public final class AnyGene<A> implements Gene<A, AnyGene<A>> {
072
073        private final A _allele;
074        private final Supplier<? extends A> _supplier;
075        private final Predicate<? super A> _validator;
076
077        private AnyGene(
078                final A allele,
079                final Supplier<? extends A> supplier,
080                final Predicate<? super A> validator
081        ) {
082                _allele = allele;
083                _supplier = requireNonNull(supplier);
084                _validator = requireNonNull(validator);
085        }
086
087        @Override
088        public A allele() {
089                return _allele;
090        }
091
092        @Override
093        public AnyGene<A> newInstance() {
094                return new AnyGene<>(_supplier.get(), _supplier, _validator);
095        }
096
097        @Override
098        public AnyGene<A> newInstance(final A value) {
099                return new AnyGene<>(value, _supplier, _validator);
100        }
101
102        @Override
103        public boolean isValid() {
104                return _validator.test(_allele);
105        }
106
107        @Override
108        public int hashCode() {
109                return hash(_allele, hash(AnyGene.class));
110        }
111
112        @Override
113        public boolean equals(final Object obj) {
114                return obj == this ||
115                        obj instanceof AnyGene<?> other &&
116                        Objects.equals(other._allele, _allele);
117        }
118
119        @Override
120        public String toString() {
121                return Objects.toString(_allele);
122        }
123
124
125        /* *************************************************************************
126         *  Static factory methods.
127         * ************************************************************************/
128
129        /**
130         * Create a new {@code AnyGene} instance with the given parameters. New
131         * (random) genes are created with the given allele {@code supplier}.
132         *
133         * @param <A> the allele type
134         * @param allele the actual allele instance the created gene represents.
135         *        {@code null} values are allowed.
136         * @param supplier the allele-supplier which is used for creating new,
137         *        random alleles
138         * @param validator the validator used for validating the created gene. This
139         *        predicate is used in the {@link #isValid()} method.
140         * @return a new {@code AnyGene} with the given parameters
141         * @throws NullPointerException if the {@code supplier} or {@code validator}
142         *         is {@code null}
143         */
144        public static <A> AnyGene<A> of(
145                final A allele,
146                final Supplier<? extends A> supplier,
147                final Predicate<? super A> validator
148        ) {
149                return new AnyGene<>(allele, supplier, validator);
150        }
151
152        /**
153         * Create a new {@code AnyGene} instance with the given parameters. New
154         * (random) genes are created with the given allele {@code supplier}. The
155         * {@code validator} predicate of the generated gene will always return
156         * {@code true}.
157         *
158         * @param <A> the allele type
159         * @param allele the actual allele instance the created gene represents.
160         *        {@code null} values are allowed.
161         * @param supplier the allele-supplier which is used for creating new,
162         *        random alleles
163         * @return a new {@code AnyGene} with the given parameters
164         * @throws NullPointerException if the {@code suppler} is {@code null}
165         */
166        public static <A> AnyGene<A> of(
167                final A allele,
168                final Supplier<? extends A> supplier
169        ) {
170                return new AnyGene<>(allele, supplier, a -> true);
171        }
172
173        /**
174         * Create a new {@code AnyGene} instance with the given allele
175         * {@code supplier}. The {@code validator} predicate of the generated gene
176         * will always return {@code true}.
177         *
178         * @param <A> the allele type
179         * @param supplier the allele-supplier which is used for creating new,
180         *        random alleles
181         * @return a new {@code AnyGene} with the given parameters
182         * @throws NullPointerException if one of the parameters is {@code null}
183         */
184        public static <A> AnyGene<A> of(final Supplier<? extends A> supplier) {
185                return new AnyGene<>(supplier.get(), supplier, a -> true);
186        }
187
188        /**
189         * Create a new {@code AnyGene} instance with the given parameters. New
190         * (random) genes are created with the given allele {@code supplier}.
191         *
192         * @param <A> the allele type
193         * @param supplier the allele-supplier which is used for creating new,
194         *        random alleles
195         * @param validator the validator used for validating the created gene. This
196         *        predicate is used in the {@link #isValid()} method.
197         * @return a new {@code AnyGene} with the given parameters
198         * @throws NullPointerException if one of the parameters is {@code null}
199         */
200        public static <A> AnyGene<A> of(
201                final Supplier<? extends A> supplier,
202                final Predicate<? super A> validator
203        ) {
204                return new AnyGene<>(supplier.get(), supplier, validator);
205        }
206
207        // Create gene sequence.
208        static <A> ISeq<AnyGene<A>> seq(
209                final IntRange lengthRange,
210                final Supplier<? extends A> supplier,
211                final Predicate<? super A> validator
212        ) {
213                final var random = random();
214                final var length = random.nextInt(lengthRange.min(), lengthRange.max());
215
216                return MSeq.<AnyGene<A>>ofLength(length)
217                        .fill(() -> of(supplier.get(), supplier, validator))
218                        .toISeq();
219        }
220
221}