001/* 002 * Java Genetic Algorithm Library (jenetics-7.2.0). 003 * Copyright (c) 2007-2023 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.function.Function; 025import java.util.function.Predicate; 026 027import io.jenetics.Gene; 028import io.jenetics.Genotype; 029import io.jenetics.util.Factory; 030 031/** 032 * This interface extends the {@link Codec} and allows to encode an object from 033 * the problem space to a corresponding {@link Genotype}, which is the 034 * <em>inverse</em> functionality of the codec. The following example shows the 035 * relation between <em>encoder</em> and <em>decoder</em> function must fulfill. 036 * 037 * <pre>{@code 038 * final InvertibleCodec<int[], IntegerGene> codec = 039 * Codecs.ofVector(IntRange.of(0, 100), 6); 040 * final int[] value = new int[]{3, 4, 6, 7, 8, 3}; 041 * final Genotype<IntegerGene> gt = codec.encode(value); 042 * assert Arrays.equals(value, codec.decode(gt)); 043 * }</pre> 044 * 045 * The main usage of an invertible codec is to simplify the definition of 046 * {@link Constraint} objects. Instead of working with the GA classes 047 * ({@link io.jenetics.Phenotype} or {@link Genotype}), it is possible to work 048 * in the <em>native</em> problem domain {@code T}. 049 * 050 * @see Constraint#of(InvertibleCodec, Predicate, Function) 051 * @see RetryConstraint#of(InvertibleCodec, Predicate, Function) 052 * @see RetryConstraint#of(InvertibleCodec, Predicate, int) 053 * 054 * @param <T> the argument type of given problem 055 * @param <G> the {@code Gene} type used for encoding the argument type {@code T} 056 * 057 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 058 * @version 5.2 059 * @since 5.2 060 */ 061public interface InvertibleCodec<T, G extends Gene<?, G>> extends Codec<T, G> { 062 063 /** 064 * Return the <em>encoder</em> function which transforms a value from the 065 * <em>native</em> problem domain back to the genotype. This is the 066 * <em>inverse</em> of the {@link #decoder()} function. The following code 067 * snippet shows how a given value in the <em>native</em> problem domain 068 * can be converted into a {@link Genotype} and transformed back. 069 * <pre>{@code 070 * final InvertibleCodec<int[], IntegerGene> codec = 071 * Codecs.ofVector(IntRange.of(0, 100), 6); 072 * final int[] value = new int[]{3, 4, 6, 7, 8, 3}; 073 * final Genotype<IntegerGene> gt = codec.encode(value); 074 * assert Arrays.equals(value, codec.decode(gt)); 075 * }</pre> 076 * 077 * @see #decoder() 078 * @see #encode(Object) 079 * 080 * @return value encoder function 081 */ 082 Function<T, Genotype<G>> encoder(); 083 084 /** 085 * Decodes the given {@code value}, which is an element of the <em>native</em> 086 * problem domain, into a {@link Genotype}. 087 * 088 * @param value the value of the <em>native</em> problem domain 089 * @return the genotype, which represents the given {@code value} 090 */ 091 default Genotype<G> encode(final T value) { 092 return encoder().apply(value); 093 } 094 095 /** 096 * Create a new {@code InvertibleCodec} with the mapped result type. 097 * 098 * This method can also be used for creating non-trivial codes like split 099 * ranges, as shown in the following example, where only values between 100 * <em>[0, 2)</em> and <em>[8, 10)</em> are valid. 101 * <pre>{@code 102 * +--+--+--+--+--+--+--+--+--+--+ 103 * | | | | | | | | | | | 104 * 0 1 2 3 4 5 6 7 8 9 10 105 * |-----|xxxxxxxxxxxxxxxxx|-----| 106 * ^ |llllllll|rrrrrrrr| ^ 107 * | | | | 108 * +-------+ +------+ 109 * }</pre> 110 * 111 * <pre>{@code 112 * final InvertibleCodec<Double, DoubleGene> codec = Codecs 113 * .ofScalar(DoubleRange.of(0, 10)) 114 * .map(v -> { 115 * if (v >= 2 && v < 8) { 116 * return v < 5 ? ((v - 2)/3)*2 : ((8 - v)/3)*2 + 8; 117 * } 118 * return v; 119 * }, 120 * Function.identity()); 121 * }</pre> 122 * 123 * @see Codec#map(Function) 124 * 125 * @param mapper the mapper function 126 * @param inverseMapper the inverse function of the {@code mapper} 127 * @param <B> the new argument type of the given problem 128 * @return a new {@link InvertibleCodec} with the mapped result type 129 * @throws NullPointerException if one the mapper is {@code null}. 130 */ 131 default <B> 132 InvertibleCodec<B, G> map( 133 final Function<? super T, ? extends B> mapper, 134 final Function<? super B, ? extends T> inverseMapper 135 ) { 136 requireNonNull(mapper); 137 requireNonNull(inverseMapper); 138 139 return InvertibleCodec.of( 140 encoding(), 141 mapper.compose(decoder()), 142 encoder().compose(inverseMapper) 143 ); 144 } 145 146 /** 147 * Create a new invertible codec from the given parameters. 148 * 149 * @param encoding the genotype factory used for creating new 150 * {@code Genotypes} 151 * @param decoder decoder function, which converts a {@link Genotype} to a 152 * value in the problem domain. 153 * @param encoder encoder function, which converts a value of the problem 154 * domain into a {@link Genotype} 155 * @param <G> the {@link Gene} type 156 * @param <T> the fitness function argument type in the problem domain 157 * @return a new {@link InvertibleCodec} object with the given parameters. 158 * @throws NullPointerException if one of the arguments is {@code null}. 159 */ 160 static <T, G extends Gene<?, G>> InvertibleCodec<T, G> of( 161 final Factory<Genotype<G>> encoding, 162 final Function<? super Genotype<G>, ? extends T> decoder, 163 final Function<? super T, Genotype<G>> encoder 164 ) { 165 requireNonNull(encoding); 166 requireNonNull(decoder); 167 requireNonNull(encoder); 168 169 return new InvertibleCodec<>() { 170 @Override 171 public Factory<Genotype<G>> encoding() { 172 return encoding; 173 } 174 175 @Override 176 @SuppressWarnings("unchecked") 177 public Function<Genotype<G>, T> decoder() { 178 return (Function<Genotype<G>, T>)decoder; 179 } 180 181 @Override 182 @SuppressWarnings("unchecked") 183 public Function<T, Genotype<G>> encoder() { 184 return (Function<T, Genotype<G>>)encoder; 185 } 186 }; 187 } 188 189}