001/* 002 * Java Genetic Algorithm Library (jenetics-8.0.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.engine; 021 022import static java.util.Objects.requireNonNull; 023 024import java.util.Optional; 025import java.util.function.Function; 026 027import io.jenetics.Gene; 028import 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 * {@snippet lang="java": 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 * } 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 */ 062public 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 understood 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 * {@snippet lang="java": 099 * final Problem<SomeObject, DoubleGene, Double> problem = null; // @replace substring='null' replacement="..." 100 * final Genotype<DoubleGene> gt = problem.codec().encoding().newInstance(); 101 * 102 * final SomeObject arg = problem.decode(gt); 103 * } 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 result = codec instanceof InvertibleCodec<T, G> ic 199 ? constraint.constrain(ic) 200 : constraint.constrain(codec); 201 } 202 203 return result; 204 } 205 206 /** 207 * Return a new optimization <i>problem</i> with the given parameters. 208 * 209 * @param fitness the problem fitness function 210 * @param codec the evolution engine codec 211 * @param <T> the (<i>native</i>) argument type of the problem fitness function 212 * @param <G> the gene type the evolution engine is working with 213 * @param <C> the result type of the fitness function 214 * @return a new problem object from the given parameters 215 * @throws NullPointerException if one of the arguments is {@code null} 216 */ 217 static <T, G extends Gene<?, G>, C extends Comparable<? super C>> 218 Problem<T, G, C> of( 219 final Function<T, C> fitness, 220 final Codec<T, G> codec 221 ) { 222 return of(fitness, codec, null); 223 } 224 225} 226