001 /*
002 * Java Genetic Algorithm Library (jenetics-6.1.0).
003 * Copyright (c) 2007-2020 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 ([email protected])
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:[email protected]">Franz Wilhelmstötter</a>
059 * @version 6.1
060 * @since 3.4
061 */
062 public interface Problem<
063 T,
064 G extends Gene<?, G>,
065 C 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 }
|