PartialAlterer.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.1.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     extends Gene<?, G>,
075     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 }