001 /*
002 * Java Genetic Algorithm Library (jenetics-5.0.0).
003 * Copyright (c) 2007-2019 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 */
020 package io.jenetics;
021
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024
025 import java.util.stream.IntStream;
026
027 import io.jenetics.internal.util.require;
028 import io.jenetics.util.ISeq;
029 import io.jenetics.util.IntRange;
030 import io.jenetics.util.MSeq;
031 import io.jenetics.util.Seq;
032
033 /**
034 * This alterer wraps a given alterer which works on a given section of the
035 * genotype's chromosomes.
036 * <pre>{@code
037 * // The genotype prototype, consisting of 4 chromosomes
038 * final Genotype<DoubleGene> gtf = Genotype.of(
039 * DoubleChromosome.of(0, 1),
040 * DoubleChromosome.of(1, 2),
041 * DoubleChromosome.of(2, 3),
042 * DoubleChromosome.of(3, 4)
043 * );
044 *
045 * // Define the GA engine.
046 * final Engine<DoubleGene, Double> engine = Engine
047 * .builder(gt -> gt.getGene().doubleValue(), gtf)
048 * .selector(new RouletteWheelSelector<>())
049 * .alterers(
050 * // The `Mutator` is used on chromosome with index 0 and 2.
051 * PartialAlterer.of(new Mutator<DoubleGene, Double>(), 0, 2),
052 * // The `MeanAlterer` is used on chromosome 3.
053 * PartialAlterer.of(new MeanAlterer<DoubleGene, Double>(), 3),
054 * // The `GaussianMutator` is used on all chromosomes.
055 * new GaussianMutator<>()
056 * )
057 * .build();
058 * }</pre>
059 *
060 * If you are using chromosome indices which are greater or equal than the
061 * number of chromosomes defined in the genotype, a
062 * {@link java.util.concurrent.CompletionException} is thrown when the evolution
063 * stream is evaluated.
064 *
065 * @implNote
066 * This alterer is slower than the performance of the wrapped alterer, because
067 * of the needed <em>sectioning</em> of the genotype.
068 *
069 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
070 * @version 5.0
071 * @since 5.0
072 */
073 public final class PartialAlterer<
074 G extends Gene<?, G>,
075 C extends Comparable<? super C>
076 >
077 implements Alterer<G, C>
078 {
079
080 private final Alterer<G, C> _alterer;
081 private final Section _section;
082
083 private PartialAlterer(final Alterer<G, C> alterer, final Section section) {
084 _alterer = requireNonNull(alterer);
085 _section = requireNonNull(section);
086 }
087
088 @Override
089 public AltererResult<G, C>
090 alter(final Seq<Phenotype<G, C>> population, final long generation) {
091 if (!population.isEmpty()) {
092 _section.checkIndices(population.get(0).getGenotype().length());
093
094 final Seq<Phenotype<G, C>> split = _section.split(population);
095 final AltererResult<G, C> result = _alterer.alter(split, generation);
096
097 return AltererResult.of(
098 _section.merge(result.getPopulation(), population),
099 result.getAlterations()
100 );
101 } else {
102 return AltererResult.of(population.asISeq(), 0);
103 }
104 }
105
106 /**
107 * Wraps the given {@code alterer}, so that it will only work on chromosomes
108 * with the given chromosome indices.
109 *
110 * @see #of(Alterer, IntRange)
111 *
112 * @param alterer the alterer to user for altering the chromosomes with the
113 * given {@code indices}
114 * @param indices the chromosomes indices (section)
115 * @param <G> the gene type
116 * @param <C> the fitness value type
117 * @return a wrapped alterer which only works for the given chromosome
118 * section
119 * @throws NullPointerException if the given {@code indices} array is
120 * {@code null}
121 * @throws IllegalArgumentException if the given {@code indices} array is
122 * empty
123 * @throws NegativeArraySizeException if one of the given {@code indices} is
124 * negative
125 */
126 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
127 Alterer<G, C> of(final Alterer<G, C> alterer, final int... indices) {
128 return new PartialAlterer<>(alterer, Section.of(indices));
129 }
130
131 /**
132 * Wraps the given {@code alterer}, so that it will only work on chromosomes
133 * with the given chromosome indices.
134 *
135 * @see #of(Alterer, int...)
136 *
137 * @param alterer the alterer to user for altering the chromosomes with the
138 * given {@code indices}
139 * @param section the half-open chromosome index range {@code [min, max)}
140 * @param <G> the gene type
141 * @param <C> the fitness value type
142 * @return a wrapped alterer which only works for the given chromosome
143 * section
144 * @throws NullPointerException if the given {@code indices} array is
145 * {@code null}
146 * @throws IllegalArgumentException if the given {@code indices} array is
147 * empty
148 * @throws NegativeArraySizeException if one of the given {@code indices} is
149 * negative
150 */
151 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
152 Alterer<G, C> of(final Alterer<G, C> alterer, final IntRange section) {
153 return new PartialAlterer<>(
154 alterer,
155 Section.of(section.stream().toArray())
156 );
157 }
158
159
160 /**
161 * The section class, which defines the chromosomes used by the alterer.
162 */
163 static final class Section {
164 final int[] indices;
165
166 private Section(final int[] indices) {
167 if (indices.length == 0) {
168 throw new IllegalArgumentException(
169 "Chromosome indices must not be empty."
170 );
171 }
172 for (int index : indices) {
173 require.nonNegative(index);
174 }
175
176 this.indices = indices;
177 }
178
179 void checkIndices(final int length) {
180 for (int index : indices) {
181 if (index >= length) {
182 throw new IndexOutOfBoundsException(format(
183 "Genotype contains %d Chromosome, but found " +
184 "SectionAlterer for Chromosome index %d.",
185 length, index
186 ));
187 }
188 }
189 }
190
191 <G extends Gene<?, G>, C extends Comparable<? super C>>
192 Seq<Phenotype<G, C>> split(final Seq<Phenotype<G, C>> population) {
193 return population.map(this::split);
194 }
195
196 <G extends Gene<?, G>, C extends Comparable<? super C>>
197 Phenotype<G, C> split(final Phenotype<G, C> phenotype) {
198 final ISeq<Chromosome<G>> chromosomes = IntStream.of(indices)
199 .mapToObj(phenotype.getGenotype()::get)
200 .collect(ISeq.toISeq());
201
202 final Genotype<G> genotype = Genotype.of(chromosomes);
203
204 return phenotype.isEvaluated()
205 ? Phenotype.of(
206 genotype,
207 phenotype.getGeneration(),
208 phenotype.getFitness())
209 : Phenotype.of(genotype, phenotype.getGeneration());
210 }
211
212 <G extends Gene<?, G>, C extends Comparable<? super C>>
213 ISeq<Phenotype<G, C>> merge(
214 final Seq<Phenotype<G, C>> section,
215 final Seq<Phenotype<G, C>> population
216 ) {
217 assert section.length() == population.length();
218
219 return IntStream.range(0, section.length())
220 .mapToObj(i -> merge(section.get(i), population.get(i)))
221 .collect(ISeq.toISeq());
222 }
223
224 <G extends Gene<?, G>, C extends Comparable<? super C>>
225 Phenotype<G, C> merge(
226 final Phenotype<G, C> section,
227 final Phenotype<G, C> phenotype
228 ) {
229 final MSeq<Chromosome<G>> chromosomes = phenotype.getGenotype()
230 .toSeq()
231 .copy();
232
233 for (int i = 0; i < indices.length; ++i) {
234 chromosomes.set(indices[i], section.getGenotype().get(i));
235 }
236
237 final Genotype<G> genotype = Genotype.of(chromosomes);
238
239 return phenotype.isEvaluated()
240 ? Phenotype.of(
241 genotype,
242 phenotype.getGeneration(),
243 phenotype.getFitness())
244 : Phenotype.of(genotype, phenotype.getGeneration());
245 }
246
247 static Section of(final int... indices) {
248 return new Section(indices);
249 }
250
251 }
252
253
254 }
|