| 
001 /*002  * Java Genetic Algorithm Library (jenetics-4.3.0).
 003  * Copyright (c) 2007-2018 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.ext;
 021
 022 import static java.lang.String.format;
 023 import static java.util.Objects.requireNonNull;
 024 import static io.jenetics.internal.util.Hashes.hash;
 025
 026 import java.io.Serializable;
 027 import java.util.Objects;
 028 import java.util.Optional;
 029
 030 import io.jenetics.util.ISeq;
 031
 032 import io.jenetics.ext.util.Tree;
 033
 034 /**
 035  * Abstract implementation of the {@link TreeGene} interface..
 036  *
 037  * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
 038  * @version 4.1
 039  * @since 3.9
 040  */
 041 public abstract class AbstractTreeGene<A, G extends AbstractTreeGene<A, G>>
 042     implements TreeGene<A, G>, Serializable
 043 {
 044
 045     private static final long serialVersionUID = 1L;
 046
 047     /**
 048      * The allele of the tree-gene.
 049      */
 050     private final A _allele;
 051     private final int _childOffset;
 052     private final int _childCount;
 053
 054     private ISeq<G> _genes;
 055
 056     /**
 057      * Creates a new tree-gene from the given data.
 058      *
 059      * @param allele the actual value (allele) of the tree-gene
 060      * @param childOffset the offset index of the child in the containing
 061      *        chromosome. If this node has no child, the value should be set
 062      *        to zero.
 063      * @param childCount the number of children of this gene
 064      * @throws IllegalArgumentException if the {@code childCount} is smaller
 065      *         than zero
 066      */
 067     protected AbstractTreeGene(
 068         final A allele,
 069         final int childOffset,
 070         final int childCount
 071     ) {
 072         if (childCount < 0) {
 073             throw new IllegalArgumentException(format(
 074                 "Child count smaller than zero: %s", childCount
 075             ));
 076         }
 077
 078         _allele = allele;
 079         _childOffset = childOffset;
 080         _childCount = childCount;
 081     }
 082
 083     /**
 084      * Return the whole flattened tree values in breadth-first order. This method
 085      * will always return the same {@code ISeq} instance.
 086      *
 087      * @return the whole flattened tree values
 088      */
 089     @Override
 090     public ISeq<G> flattenedNodes() {
 091         return _genes;
 092     }
 093
 094     @Override
 095     public G getRoot() {
 096         return _genes.get(0);
 097     }
 098
 099     @Override
 100     public boolean isRoot() {
 101         return getRoot() == this;
 102     }
 103
 104     @Override
 105     public int size() {
 106         return isRoot() ? _genes.size() : TreeGene.super.size();
 107     }
 108
 109     protected void checkTreeState() {
 110         if (_genes == null) {
 111             throw new IllegalStateException(
 112                 "Gene is not attached to a chromosome."
 113             );
 114         }
 115     }
 116
 117     /**
 118      * This method is used by the {@code AbstractTreeChromosome} to attach
 119      * itself to this gene.
 120      *
 121      * @param genes the genes of the attached chromosome
 122      */
 123     protected void bind(final ISeq<G> genes) {
 124         _genes = requireNonNull(genes);
 125     }
 126
 127     @Override
 128     public int childOffset() {
 129         return _childOffset;
 130     }
 131
 132     @Override
 133     public A getAllele() {
 134         return _allele;
 135     }
 136
 137     /**
 138      * Return the <em>parent</em> node of this tree node.
 139      *
 140      * @return the parent node, or {@code Optional.empty()} if this node is the
 141      *         root of the tree
 142      * @throws IllegalStateException if this gene is not part of a chromosome
 143      */
 144     @Override
 145     public Optional<G> getParent() {
 146         checkTreeState();
 147
 148         return _genes.stream()
 149             .filter(g -> g.childStream().anyMatch(this::identical))
 150             .findFirst();
 151     }
 152
 153     /**
 154      * Return the child gene with the given index.
 155      *
 156      * @param index the child index
 157      * @return the child node with the given index
 158      * @throws IndexOutOfBoundsException  if the {@code index} is out of
 159      *         bounds ({@code [0, childCount())})
 160      * @throws IllegalStateException if this gene is not part of a chromosome
 161      */
 162     @Override
 163     public G getChild(final int index) {
 164         checkTreeState();
 165         if (index < 0 || index >= childCount()) {
 166             throw new IndexOutOfBoundsException(format(
 167                 "Child index out of bounds: %s", index
 168             ));
 169         }
 170
 171         assert _genes != null;
 172         return _genes.get(_childOffset + index);
 173     }
 174
 175     @Override
 176     public int childCount() {
 177         return _childCount;
 178     }
 179
 180     @Override
 181     public boolean isValid() {
 182         return _genes != null;
 183     }
 184
 185     @Override
 186     public boolean identical(final Tree<?, ?> other) {
 187         return other instanceof AbstractTreeGene &&
 188             Objects.equals(((AbstractTreeGene)other)._allele, _allele) &&
 189             ((AbstractTreeGene)other)._genes == _genes &&
 190             ((AbstractTreeGene)other)._childOffset == _childOffset &&
 191             ((AbstractTreeGene)other)._childCount == _childCount;
 192     }
 193
 194     @Override
 195     public int hashCode() {
 196         return hash(_allele, hash(_childOffset, hash(_childCount)));
 197     }
 198
 199     @Override
 200     public boolean equals(final Object obj) {
 201         return obj == this ||
 202             obj instanceof AbstractTreeGene &&
 203             Objects.equals(((AbstractTreeGene)obj)._allele, _allele) &&
 204             ((AbstractTreeGene)obj)._childOffset == _childOffset &&
 205             ((AbstractTreeGene)obj)._childCount == _childCount;
 206     }
 207
 208     @Override
 209     public String toString() {
 210         return Objects.toString(_allele);
 211     }
 212
 213 }
 |