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