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.ext.grammar; 021 022import static java.util.Objects.requireNonNull; 023 024import java.util.concurrent.atomic.AtomicInteger; 025import java.util.function.IntUnaryOperator; 026 027import io.jenetics.BitChromosome; 028import io.jenetics.BitGene; 029import io.jenetics.IntegerGene; 030import io.jenetics.internal.util.Bits; 031import io.jenetics.internal.util.Requires; 032import io.jenetics.util.BaseSeq; 033 034import io.jenetics.ext.grammar.Cfg.Rule; 035 036/** 037 * Represents a mapping of a finite set of integers to symbol indexes. If more 038 * indexes are needed, the values are read from the beginning again. You have 039 * the possibility to create a {@code Codons} object from different chromosome 040 * types. 041 * {@snippet lang="java": 042 * // Create 'classic' codons from a bit-chromosome, where 043 * // the genes are split into 8-bit junks and converted 044 * // into unsigned int values. 045 * final Codons codons = Codons.ofBitGenes(BitChromosome.of(10_000)); 046 * 047 * // Creating a codons object from an integer chromosome. 048 * final var ich = IntegerChromosome.of(IntRange.of(0, 256), 1_000); 049 * final var codons = Codons.ofIntegerGenes(ich); 050 * } 051 * 052 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 053 * @since 7.1 054 * @version 7.1 055 */ 056public final class Codons implements SymbolIndex { 057 058 private final IntUnaryOperator _values; 059 private final int _length; 060 061 private final AtomicInteger _pos = new AtomicInteger(0); 062 063 /** 064 * Create a new {@code Codons} object from a given {@code codons} source and 065 * its {@code length}. 066 * 067 * @param codons the codon source 068 * @param length the length of the codon source 069 * @throws NullPointerException if the {@code codons} source is {@code null} 070 * @throws IllegalArgumentException if the given {@code length} is smaller 071 * than one 072 */ 073 public Codons(final IntUnaryOperator codons, final int length) { 074 _values = requireNonNull(codons); 075 _length = Requires.positive(length); 076 } 077 078 @Override 079 public int next(final Rule<?> rule, final int bound) { 080 final int index = _pos.getAndUpdate(x -> (x + 1)%_length); 081 return _values.applyAsInt(index)%bound; 082 } 083 084 /** 085 * Creates a new, classical <em>codons</em> object from the given bit-genes. 086 * The genes is split into 8-bit chunks and converted into an unsigned 087 * {@code int[]} array. 088 * {@snippet lang="java": 089 * final Codons codons = Codons.ofBitGenes(BitChromosome.of(10_000)); 090 * } 091 * 092 * @param genes the genes used for creating the codon object 093 * @return a new <em>codons</em> object 094 */ 095 public static Codons ofBitGenes(final BaseSeq<BitGene> genes) { 096 if (genes instanceof BitChromosome ch) { 097 return ofBytes(ch.toByteArray()); 098 } else { 099 return ofBytes(toByteArray(genes)); 100 } 101 } 102 103 private static Codons ofBytes(final byte[] bytes) { 104 final var values = new int[bytes.length]; 105 for (int i = 0; i < values.length; ++i) { 106 values[i] = Byte.toUnsignedInt(bytes[i]); 107 } 108 109 return new Codons(i -> values[i], values.length); 110 } 111 112 static byte[] toByteArray(final BaseSeq<BitGene> genes) { 113 final byte[] bytes = Bits.newArray(genes.length()); 114 for (int i = 0; i < genes.length(); ++i) { 115 if (genes.get(i).booleanValue()) { 116 Bits.set(bytes, i); 117 } 118 } 119 120 return bytes; 121 } 122 123 /** 124 * Creates a new <em>codons</em> object from the given int-genes. 125 * 126 * {@snippet lang="java": 127 * final var chromosome = IntegerChromosome.of(IntRange.of(0, 256), 1_000); 128 * final var codons = Codons.ofIntegerGenes(chromosome); 129 * } 130 * 131 * @param genes the genes used for creating the codon object 132 * @return a new <em>codons</em> object 133 */ 134 public static Codons ofIntegerGenes(final BaseSeq<IntegerGene> genes) { 135 return new Codons(i -> genes.get(i).intValue(), genes.length()); 136 } 137 138}