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