CompositeCodec.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.5.0).
003  * Copyright (c) 2007-2016 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@gmx.at)
019  */
020 package org.jenetics.engine;
021 
022 import static java.util.Objects.requireNonNull;
023 
024 import java.util.function.Function;
025 
026 import org.jenetics.Chromosome;
027 import org.jenetics.Gene;
028 import org.jenetics.Genotype;
029 import org.jenetics.util.Factory;
030 import org.jenetics.util.ISeq;
031 
032 /**
033  * Composites a list of codecs into one {@code Codec} class.
034  *
035  * @param <G> the gene type
036  * @param <T> the argument type of the compound codec
037  *
038  * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
039  * @version 3.3
040  * @since 3.3
041  */
042 final class CompositeCodec<T, G extends Gene<?, G>> implements Codec<T, G> {
043 
044     private final ISeq<? extends Codec<?, G>> _codecs;
045     private final Function<? super Object[], ? extends T> _decoder;
046 
047     private final int[] _lengths;
048     private final Genotype<G> _encoding;
049 
050     /**
051      * Combines the given {@code codecs} into one codec. This lets you divide
052      * a problem into sub problems and combine them again.
053      *
054      * @param codecs the {@code Codec} sequence of the sub-problems
055      * @param decoder the decoder which combines the argument types from the
056      *        given given codecs, to the argument type of the resulting codec.
057      * @throws NullPointerException if one of the arguments is {@code null}
058      */
059     CompositeCodec(
060         final ISeq<? extends Codec<?, G>> codecs,
061         final Function<? super Object[], ? extends T> decoder
062     ) {
063         _codecs = requireNonNull(codecs);
064         _decoder = requireNonNull(decoder);
065 
066         final ISeq<Genotype<G>> genotypes = _codecs
067             .map(c -> c.encoding() instanceof Genotype<?>
068                 ? (Genotype<G>)c.encoding()
069                 : c.encoding().newInstance());
070 
071         _lengths = genotypes.stream()
072             .mapToInt(Genotype::length)
073             .toArray();
074 
075         _encoding = Genotype.of(
076                 genotypes.stream()
077                     .flatMap(Genotype::stream)
078                     .collect(ISeq.toISeq())
079             );
080     }
081 
082     @Override
083     public Factory<Genotype<G>> encoding() {
084         return _encoding;
085     }
086 
087     @Override
088     public Function<Genotype<G>, T> decoder() {
089         return gt -> _decoder.apply(groups(gt));
090     }
091 
092     private Object[] groups(final Genotype<G> genotype) {
093         final Object[] groups = new Object[_codecs.length()];
094         final ISeq<Chromosome<G>> chromosomes = genotype.toSeq();
095 
096         int start = 0;
097         for (int i = 0; i < _codecs.length(); ++i) {
098             final int end = start + _lengths[i];
099             final Genotype<G> gt = Genotype.of(chromosomes.subSeq(start, end));
100 
101             groups[i] = _codecs.get(i).decoder().apply(gt);
102             start = end;
103         }
104 
105         return groups;
106     }
107 
108 }