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