Problem.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-6.3.0).
003  * Copyright (c) 2007-2021 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.engine;
021 
022 import static java.util.Objects.requireNonNull;
023 
024 import java.util.Optional;
025 import java.util.function.Function;
026 
027 import io.jenetics.Gene;
028 import io.jenetics.Genotype;
029 
030 /**
031  * This interface describes a <i>problem</i> which can be solved by the GA
032  * evolution {@code Engine}. It connects the actual {@link #fitness()} function
033  * and the needed {@link #codec()}.
034  *
035  <pre>{@code
036  * final Problem<ISeq<BitGene>, BitGene, Integer> counting = Problem.of(
037  *     // Native fitness function
038  *     genes -> (int)genes.stream()
039  *         .filter(BitGene::bit)
040  *         .count(),
041  *     // Problem encoding
042  *     Codec.of(
043  *         Genotype.of(BitChromosome.of(100)),
044  *         gt -> ISeq.of(gt.chromosome())
045  *     )
046  * );
047  * }</pre>
048  *
049  * The example above shows the Ones-Counting problem definition.
050  *
051  @see Codec
052  @see Engine
053  *
054  @param <T> the (<i>native</i>) argument type of the problem fitness function
055  @param <G> the gene type the evolution engine is working with
056  @param <C> the result type of the fitness function
057  *
058  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
059  @version 6.1
060  @since 3.4
061  */
062 public interface Problem<
063     T,
064     extends Gene<?, G>,
065     extends Comparable<? super C>
066 {
067 
068     /**
069      * Return the fitness function of the <i>problem</i> in the <i>native</i>
070      * problem domain.
071      *
072      @return the fitness function
073      */
074     Function<T, C> fitness();
075 
076     /**
077      * Return the codec, which translates the types of the problem domain into
078      * types, which can be understand by the evolution {@code Engine}.
079      *
080      @return the engine codec
081      */
082     Codec<T, G> codec();
083 
084     /**
085      * Return the constraint, associated with {@code this} problem, if available.
086      *
087      @since 6.1
088      *
089      @return the constraint, associated with {@code this} problem
090      */
091     default Optional<Constraint<G, C>> constraint() {
092         return Optional.empty();
093     }
094 
095     /**
096      * Converts the given {@link Genotype} to the target type {@link T}. This is
097      * a shortcut for
098      <pre>{@code
099      * final Problem<SomeObject, DoubleGene, Double> problem = ...
100      * final Genotype<DoubleGene> gt = problem.codec().encoding().newInstance();
101      *
102      * final SomeObject arg = problem.decode(gt);
103      * }</pre>
104      *
105      @since 4.2
106      *
107      @see Codec#decode(Genotype)
108      *
109      @param genotype the genotype to be converted
110      @return the converted genotype
111      @throws NullPointerException if the given {@code genotype} is {@code null}
112      */
113     default T decode(final Genotype<G> genotype) {
114         return codec().decode(genotype);
115     }
116 
117     /**
118      * Returns the fitness value for the given argument.
119      *
120      @since 4.1
121      *
122      @param arg the argument of the fitness function
123      @return the fitness value
124      */
125     default C fitness(final T arg) {
126         return fitness().apply(arg);
127     }
128 
129     /**
130      * Returns the fitness value for the given argument.
131      *
132      @since 4.1
133      *
134      @param genotype the argument of the fitness function
135      @return the fitness value
136      */
137     default C fitness(final Genotype<G> genotype) {
138         return fitness(codec().decode(genotype));
139     }
140 
141     /**
142      * Return a new optimization <i>problem</i> with the given parameters. The
143      * given {@code constraint} is applied to the {@link Engine}, via
144      {@link Engine.Builder#constraint(Constraint)}, and the {@link Codec}, via
145      {@link Constraint#constrain(Codec)}.
146      <p>
147      <b>Note</b><br>
148      *     When creating a new {@code Problem} instance with this factory method,
149      *     there is no need for additionally <em>constraining</em> the given
150      *     {@code codec} with {@link Constraint#constrain(Codec)}.
151      *
152      @since 6.1
153      *
154      @see Engine.Builder#constraint(Constraint)
155      @see Constraint#constrain(Codec)
156      *
157      @param fitness the problem fitness function
158      @param codec the evolution engine codec
159      @param constraint the problem constraint, may be {@code null}
160      @param <T> the (<i>native</i>) argument type of the problem fitness function
161      @param <G> the gene type the evolution engine is working with
162      @param <C> the result type of the fitness function
163      @return a new problem object from the given parameters
164      @throws NullPointerException if the {@code fitness} or {@code codec} is
165      *         {@code null}
166      */
167     static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
168     Problem<T, G, C> of(
169         final Function<T, C> fitness,
170         final Codec<T, G> codec,
171         final Constraint<G, C> constraint
172     ) {
173         requireNonNull(fitness);
174         requireNonNull(codec);
175 
176         final var constrainedCodec = wrap(constraint, codec);
177 
178         return new Problem<>() {
179             @Override
180             public Codec<T, G> codec() {
181                 return constrainedCodec;
182             }
183             @Override
184             public Function<T, C> fitness() {
185                 return fitness;
186             }
187             @Override
188             public Optional<Constraint<G, C>> constraint() {
189                 return Optional.ofNullable(constraint);
190             }
191         };
192     }
193 
194     private static  <T, G extends Gene<?, G>, C extends Comparable<? super C>>
195     Codec<T, G> wrap(final Constraint<G, C> constraint, final Codec<T, G> codec) {
196         Codec<T, G> result = codec;
197         if (constraint != null) {
198             if (codec instanceof InvertibleCodec) {
199                 result = constraint.constrain((InvertibleCodec<T, G>)codec);
200             else {
201                 result = constraint.constrain(codec);
202             }
203         }
204 
205         return result;
206     }
207 
208     /**
209      * Return a new optimization <i>problem</i> with the given parameters.
210      *
211      @param fitness the problem fitness function
212      @param codec the evolution engine codec
213      @param <T> the (<i>native</i>) argument type of the problem fitness function
214      @param <G> the gene type the evolution engine is working with
215      @param <C> the result type of the fitness function
216      @return a new problem object from the given parameters
217      @throws NullPointerException if one of the arguments is {@code null}
218      */
219     static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
220     Problem<T, G, C> of(
221         final Function<T, C> fitness,
222         final Codec<T, G> codec
223     ) {
224         return of(fitness, codec, null);
225     }
226 
227 }