All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jenetics.ext.grammar.MultiIntegerChromosomeMapper Maven / Gradle / Ivy

The newest version!
/*
 * Java Genetic Algorithm Library (jenetics-8.1.0).
 * Copyright (c) 2007-2024 Franz Wilhelmstötter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author:
 *    Franz Wilhelmstötter ([email protected])
 */
package io.jenetics.ext.grammar;

import static java.util.Objects.requireNonNull;

import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import io.jenetics.Genotype;
import io.jenetics.IntegerChromosome;
import io.jenetics.IntegerGene;
import io.jenetics.engine.Codec;
import io.jenetics.util.Factory;
import io.jenetics.util.ISeq;
import io.jenetics.util.IntRange;

import io.jenetics.ext.grammar.Cfg.Rule;

/**
 * Codec for creating results from a given grammar. The creation of
 * the grammar result is controlled by a given genotype. This encoding uses
 * separate codons, backed up by a {@link IntegerChromosome}, for
 * every rule. The length of the chromosome is defined as a function of the
 * encoded rules. This means that the following CFG,
 *
 * 
{@code
 *                       (0)            (1)
 * (0)  ::= () | 
 *               (0) (1) (2) (3)
 * (1)    ::= + | - | * | /
 *               (0) (1) (2) (3) (4)
 * (2)   ::= x | 1 | 2 | 3 | 4
 * }
* * will be represented by the following {@link Genotype} * {@snippet lang="java": * Genotype.of( * IntegerChromosome.of(IntRange.of(0, 2), length.apply(cfg.rules().get(0))), * IntegerChromosome.of(IntRange.of(0, 4), length.apply(cfg.rules().get(1))), * IntegerChromosome.of(IntRange.of(0, 5), length.apply(cfg.rules().get(2))) * ) * } * * The {@code length} function lets you defining the number of codons as * function of the rule the chromosome is encoding. * * {@snippet lang="java": * final Cfg cfg = Bnf.parse(null); // @replace substring='null' replacement="..." * final Codec>, IntegerGene> codec = new Mapper<>( * cfg, * // The chromosome length is 10 times the * // number of rule alternatives. * rule -> IntRange.of(rule.alternatives().size()*10), * // Using the standard sentence generator * // with a maximal sentence length of 5,000. * index -> new SentenceGenerator<>(index, 5_000) * ); * } * * @param the terminal token type of the grammar * @param the result type of the mapper * * @author Franz Wilhelmstötter * @since 7.1 * @version 7.1 */ final class MultiIntegerChromosomeMapper implements Codec { private final Factory> _encoding; private final Function, R> _decoder; /** * Create a new sentence (list of terminal symbols) codec. * * @param cfg the encoding grammar * @param length the length of the chromosome which is used for selecting * rules and symbols. The input parameter for this function is the * actual rule. This way it is possible to define the chromosome * length dependent on the selectable alternatives. * @param generator sentence generator function from a given * {@link SymbolIndex} */ public MultiIntegerChromosomeMapper( final Cfg cfg, final Function, IntRange> length, final Function> generator ) { // Every rule gets its own codons. The ranges of the chromosomes // will fit exactly the number of rule alternatives. _encoding = Genotype.of( cfg.rules().stream() .map(rule -> IntegerChromosome.of( IntRange.of(0, rule.alternatives().size()), length.apply(rule) )) .collect(ISeq.toISeq()) ); final var codons = new CodonsFactory(cfg); _decoder = gt -> generator.apply(codons.get(gt)).generate(cfg); } @Override public Factory> encoding() { return _encoding; } @Override public Function, R> decoder() { return _decoder; } /** * Helper class for generating codons for a given genotype. */ private static final class CodonsFactory { private final Map _rulesIndex; CodonsFactory(final Cfg cfg) { _rulesIndex = IntStream .range(0, cfg.rules().size()) .mapToObj(i -> Map.entry(cfg.rules().get(i).start().name(), i)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } SymbolIndex get(final Genotype gt) { final var codons = new CodonsCache(gt); return (rule, bound) -> codons .get(_rulesIndex.get(rule.start().name())) .next(rule, bound); } /** * Caching and lazy creation of codons. */ private static final class CodonsCache { private final Genotype _genotype; private final Codons[] _codons; CodonsCache(final Genotype genotype) { _genotype = requireNonNull(genotype); _codons = new Codons[genotype.length()]; } Codons get(final int index) { Codons result = _codons[index]; if (result == null) { result = Codons.ofIntegerGenes(_genotype.get(index)); _codons[index] = result; } return result; } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy