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