| 1 | package net.bmahe.genetics4j.core.chromosomes; | |
| 2 | ||
| 3 | import java.util.ArrayList; | |
| 4 | import java.util.Collection; | |
| 5 | import java.util.Comparator; | |
| 6 | import java.util.List; | |
| 7 | import java.util.stream.Collectors; | |
| 8 | ||
| 9 | import org.apache.commons.lang3.Validate; | |
| 10 | ||
| 11 | /** | |
| 12 | * Represents a node in a tree structure used for genetic programming and tree-based chromosomes. | |
| 13 | * | |
| 14 | * <p>TreeNode provides a flexible, generic tree data structure that forms the foundation for tree-based genetic | |
| 15 | * programming operations. Each node contains data of a specified type and can have zero or more child nodes, enabling | |
| 16 | * the representation of complex hierarchical structures such as mathematical expressions, decision trees, or program | |
| 17 | * syntax trees. | |
| 18 | * | |
| 19 | * <p>Key features include: | |
| 20 | * <ul> | |
| 21 | * <li><strong>Generic data storage</strong>: Can hold any type of data (functions, terminals, values)</li> | |
| 22 | * <li><strong>Dynamic structure</strong>: Supports adding, removing, and modifying children</li> | |
| 23 | * <li><strong>Tree metrics</strong>: Provides size and depth calculations for analysis</li> | |
| 24 | * <li><strong>Hierarchical operations</strong>: Enables tree traversal and manipulation</li> | |
| 25 | * </ul> | |
| 26 | * | |
| 27 | * <p>Common uses in genetic programming: | |
| 28 | * <ul> | |
| 29 | * <li><strong>Expression trees</strong>: Mathematical or logical expressions with operators and operands</li> | |
| 30 | * <li><strong>Program trees</strong>: Structured representation of executable code or algorithms</li> | |
| 31 | * <li><strong>Decision trees</strong>: Conditional logic structures for classification or control</li> | |
| 32 | * <li><strong>Grammar trees</strong>: Parse trees representing valid grammatical constructs</li> | |
| 33 | * </ul> | |
| 34 | * | |
| 35 | * <p>Tree structure characteristics: | |
| 36 | * <ul> | |
| 37 | * <li><strong>Mutable structure</strong>: Children can be added, removed, or replaced during evolution</li> | |
| 38 | * <li><strong>Type safety</strong>: Generic parameterization ensures consistent data types</li> | |
| 39 | * <li><strong>Recursive operations</strong>: Size and depth calculations traverse the entire subtree</li> | |
| 40 | * <li><strong>Equality semantics</strong>: Two trees are equal if their structure and data match</li> | |
| 41 | * </ul> | |
| 42 | * | |
| 43 | * <p>Example usage in genetic programming: | |
| 44 | * | |
| 45 | * <pre>{@code | |
| 46 | * // Creating a simple mathematical expression: (x + 2) * 3 | |
| 47 | * TreeNode<String> multiply = new TreeNode<>("*"); | |
| 48 | * TreeNode<String> add = new TreeNode<>("+"); | |
| 49 | * TreeNode<String> x = new TreeNode<>("x"); | |
| 50 | * TreeNode<String> two = new TreeNode<>("2"); | |
| 51 | * TreeNode<String> three = new TreeNode<>("3"); | |
| 52 | * | |
| 53 | * add.addChild(x); | |
| 54 | * add.addChild(two); | |
| 55 | * multiply.addChild(add); | |
| 56 | * multiply.addChild(three); | |
| 57 | * | |
| 58 | * // Tree metrics | |
| 59 | * int treeSize = multiply.getSize(); // Total nodes in tree | |
| 60 | * int treeDepth = multiply.getDepth(); // Maximum depth from root | |
| 61 | * | |
| 62 | * // Factory method for creating nodes with children | |
| 63 | * TreeNode<String> expression = TreeNode.of("*", | |
| 64 | * List.of(TreeNode.of("+", List.of(new TreeNode<>("x"), new TreeNode<>("2"))), new TreeNode<>("3"))); | |
| 65 | * }</pre> | |
| 66 | * | |
| 67 | * <p>Integration with genetic operations: | |
| 68 | * <ul> | |
| 69 | * <li><strong>Crossover</strong>: Subtree exchange between parent trees</li> | |
| 70 | * <li><strong>Mutation</strong>: Replacement or modification of individual nodes or subtrees</li> | |
| 71 | * <li><strong>Size constraints</strong>: Enforcement of maximum tree size or depth limits</li> | |
| 72 | * <li><strong>Evaluation</strong>: Tree traversal for fitness computation</li> | |
| 73 | * </ul> | |
| 74 | * | |
| 75 | * <p>Performance considerations: | |
| 76 | * <ul> | |
| 77 | * <li><strong>Memory usage</strong>: Each node maintains a list of children references</li> | |
| 78 | * <li><strong>Tree traversal</strong>: Size and depth calculations have O(n) complexity</li> | |
| 79 | * <li><strong>Structural sharing</strong>: Nodes can be shared between trees with care</li> | |
| 80 | * <li><strong>Deep trees</strong>: Very deep trees may cause stack overflow in recursive operations</li> | |
| 81 | * </ul> | |
| 82 | * | |
| 83 | * @param <T> the type of data stored in each node | |
| 84 | * @see TreeChromosome | |
| 85 | * @see TreeChromosome | |
| 86 | */ | |
| 87 | public class TreeNode<T> { | |
| 88 | ||
| 89 | private final T data; | |
| 90 | ||
| 91 | private ArrayList<TreeNode<T>> children; | |
| 92 | ||
| 93 | /** | |
| 94 | * Constructs a new tree node with the specified data and no children. | |
| 95 | * | |
| 96 | * <p>Creates a leaf node that can later have children added to it. The data provided becomes the payload for this | |
| 97 | * node and cannot be changed after construction. | |
| 98 | * | |
| 99 | * @param _data the data to store in this node | |
| 100 | * @throws IllegalArgumentException if data is null | |
| 101 | */ | |
| 102 | public TreeNode(final T _data) { | |
| 103 | Validate.notNull(_data); | |
| 104 | ||
| 105 |
1
1. <init> : Removed assignment to member variable data → KILLED |
this.data = _data; |
| 106 |
2
1. <init> : Removed assignment to member variable children → KILLED 2. <init> : removed call to java/util/ArrayList::<init> → KILLED |
this.children = new ArrayList<>(); |
| 107 | } | |
| 108 | ||
| 109 | /** | |
| 110 | * Returns the data stored in this node. | |
| 111 | * | |
| 112 | * @return the data payload of this node | |
| 113 | */ | |
| 114 | public T getData() { | |
| 115 |
1
1. getData : replaced return value with null for net/bmahe/genetics4j/core/chromosomes/TreeNode::getData → KILLED |
return data; |
| 116 | } | |
| 117 | ||
| 118 | /** | |
| 119 | * Returns the list of direct children of this node. | |
| 120 | * | |
| 121 | * <p>The returned list is the actual internal list used by this node. Modifications to the returned list will affect | |
| 122 | * this node's structure. | |
| 123 | * | |
| 124 | * @return the mutable list of child nodes | |
| 125 | */ | |
| 126 | public List<TreeNode<T>> getChildren() { | |
| 127 |
1
1. getChildren : replaced return value with Collections.emptyList for net/bmahe/genetics4j/core/chromosomes/TreeNode::getChildren → KILLED |
return children; |
| 128 | } | |
| 129 | ||
| 130 | /** | |
| 131 | * Returns the child node at the specified index. | |
| 132 | * | |
| 133 | * @param childIndex the index of the child to retrieve (0-based) | |
| 134 | * @return the child node at the specified index | |
| 135 | * @throws IllegalArgumentException if childIndex is negative | |
| 136 | * @throws IndexOutOfBoundsException if childIndex is >= number of children | |
| 137 | */ | |
| 138 | public TreeNode<T> getChild(final int childIndex) { | |
| 139 | Validate.isTrue(childIndex >= 0); | |
| 140 | ||
| 141 |
2
1. getChild : replaced return value with null for net/bmahe/genetics4j/core/chromosomes/TreeNode::getChild → KILLED 2. getChild : removed call to java/util/ArrayList::get → KILLED |
return children.get(childIndex); |
| 142 | } | |
| 143 | ||
| 144 | /** | |
| 145 | * Replaces the child node at the specified index with a new node. | |
| 146 | * | |
| 147 | * <p>This operation modifies the tree structure by replacing an existing child with a new subtree rooted at the | |
| 148 | * provided node. | |
| 149 | * | |
| 150 | * @param childIndex the index of the child to replace (0-based) | |
| 151 | * @param childData the new child node to set at the specified index | |
| 152 | * @throws IllegalArgumentException if childIndex is negative | |
| 153 | * @throws IndexOutOfBoundsException if childIndex is >= number of children | |
| 154 | */ | |
| 155 | public void setChild(final int childIndex, final TreeNode<T> childData) { | |
| 156 | Validate.isTrue(childIndex >= 0); | |
| 157 | ||
| 158 |
2
1. setChild : replaced call to java/util/ArrayList::set with argument → NO_COVERAGE 2. setChild : removed call to java/util/ArrayList::set → NO_COVERAGE |
children.set(childIndex, childData); |
| 159 | } | |
| 160 | ||
| 161 | /** | |
| 162 | * Adds a new child node to this node. | |
| 163 | * | |
| 164 | * <p>The new child is appended to the end of the children list. This operation increases the arity of this node by | |
| 165 | * one. | |
| 166 | * | |
| 167 | * @param childData the child node to add | |
| 168 | * @throws IllegalArgumentException if childData is null | |
| 169 | */ | |
| 170 | public void addChild(final TreeNode<T> childData) { | |
| 171 | Validate.notNull(childData); | |
| 172 | ||
| 173 |
1
1. addChild : removed call to java/util/ArrayList::add → KILLED |
children.add(childData); |
| 174 | } | |
| 175 | ||
| 176 | /** | |
| 177 | * Adds multiple child nodes to this node. | |
| 178 | * | |
| 179 | * <p>All nodes in the provided collection are appended to the children list in the order they appear in the | |
| 180 | * collection. | |
| 181 | * | |
| 182 | * @param childrenNodes the collection of child nodes to add | |
| 183 | * @throws IllegalArgumentException if childrenNodes is null or empty | |
| 184 | */ | |
| 185 | public void addChildren(final Collection<TreeNode<T>> childrenNodes) { | |
| 186 | Validate.notNull(childrenNodes); | |
| 187 | Validate.isTrue(childrenNodes.isEmpty() == false); | |
| 188 | ||
| 189 |
1
1. addChildren : removed call to java/util/ArrayList::addAll → NO_COVERAGE |
children.addAll(childrenNodes); |
| 190 | } | |
| 191 | ||
| 192 | /** | |
| 193 | * Returns the total number of nodes in the subtree rooted at this node. | |
| 194 | * | |
| 195 | * <p>This method recursively counts all nodes in the subtree, including this node and all its descendants. The size | |
| 196 | * is useful for analyzing tree complexity and implementing size-based genetic operations. | |
| 197 | * | |
| 198 | * @return the total number of nodes in this subtree (always >= 1) | |
| 199 | */ | |
| 200 | public int getSize() { | |
| 201 |
3
1. getSize : removed call to java/util/ArrayList::stream → KILLED 2. getSize : replaced int return with 0 for net/bmahe/genetics4j/core/chromosomes/TreeNode::getSize → KILLED 3. getSize : Substituted 1 with 0 → KILLED |
return 1 + children.stream() |
| 202 |
2
1. getSize : replaced call to java/util/stream/Stream::map with receiver → KILLED 2. getSize : removed call to java/util/stream/Stream::map → KILLED |
.map(TreeNode::getSize) |
| 203 |
6
1. getSize : removed call to java/util/stream/Collectors::summingInt → KILLED 2. getSize : removed call to java/lang/Integer::intValue → KILLED 3. lambda$getSize$0 : replaced int return with 0 for net/bmahe/genetics4j/core/chromosomes/TreeNode::lambda$getSize$0 → KILLED 4. getSize : removed call to java/util/stream/Stream::collect → KILLED 5. lambda$getSize$0 : removed call to java/lang/Integer::intValue → KILLED 6. getSize : Replaced integer addition with subtraction → KILLED |
.collect(Collectors.summingInt(x -> x)); |
| 204 | } | |
| 205 | ||
| 206 | /** | |
| 207 | * Returns the maximum depth of the subtree rooted at this node. | |
| 208 | * | |
| 209 | * <p>The depth is defined as the length of the longest path from this node to any leaf node in the subtree. A leaf | |
| 210 | * node has depth 1. | |
| 211 | * | |
| 212 | * @return the maximum depth of this subtree (always >= 1) | |
| 213 | */ | |
| 214 | public int getDepth() { | |
| 215 |
3
1. getDepth : removed call to java/util/ArrayList::stream → KILLED 2. getDepth : Substituted 1 with 0 → KILLED 3. getDepth : replaced int return with 0 for net/bmahe/genetics4j/core/chromosomes/TreeNode::getDepth → KILLED |
return 1 + children.stream() |
| 216 |
2
1. getDepth : replaced call to java/util/stream/Stream::map with receiver → KILLED 2. getDepth : removed call to java/util/stream/Stream::map → KILLED |
.map(TreeNode::getDepth) |
| 217 |
3
1. getDepth : removed call to java/util/stream/Stream::max → KILLED 2. getDepth : removed call to java/util/Comparator::naturalOrder → KILLED 3. getDepth : Substituted 0 with 1 → KILLED |
.max(Comparator.naturalOrder()) |
| 218 |
5
1. getDepth : Replaced integer addition with subtraction → KILLED 2. getDepth : removed call to java/lang/Integer::intValue → KILLED 3. getDepth : removed call to java/lang/Integer::valueOf → KILLED 4. getDepth : removed call to java/util/Optional::orElse → KILLED 5. getDepth : replaced call to java/util/Optional::orElse with argument → KILLED |
.orElse(0); |
| 219 | } | |
| 220 | ||
| 221 | @Override | |
| 222 | public int hashCode() { | |
| 223 |
1
1. hashCode : Substituted 31 with 32 → NO_COVERAGE |
final int prime = 31; |
| 224 |
1
1. hashCode : Substituted 1 with 0 → NO_COVERAGE |
int result = 1; |
| 225 |
8
1. hashCode : removed call to java/util/ArrayList::hashCode → NO_COVERAGE 2. hashCode : removed conditional - replaced equality check with false → NO_COVERAGE 3. hashCode : Replaced integer multiplication with division → NO_COVERAGE 4. hashCode : Substituted 0 with 1 → NO_COVERAGE 5. hashCode : negated conditional → NO_COVERAGE 6. hashCode : Replaced integer addition with subtraction → NO_COVERAGE 7. hashCode : Substituted 31 with 32 → NO_COVERAGE 8. hashCode : removed conditional - replaced equality check with true → NO_COVERAGE |
result = prime * result + ((children == null) ? 0 : children.hashCode()); |
| 226 |
8
1. hashCode : negated conditional → NO_COVERAGE 2. hashCode : removed conditional - replaced equality check with true → NO_COVERAGE 3. hashCode : Replaced integer multiplication with division → NO_COVERAGE 4. hashCode : Substituted 0 with 1 → NO_COVERAGE 5. hashCode : Substituted 31 with 32 → NO_COVERAGE 6. hashCode : Replaced integer addition with subtraction → NO_COVERAGE 7. hashCode : removed conditional - replaced equality check with false → NO_COVERAGE 8. hashCode : removed call to java/lang/Object::hashCode → NO_COVERAGE |
result = prime * result + ((data == null) ? 0 : data.hashCode()); |
| 227 |
1
1. hashCode : replaced int return with 0 for net/bmahe/genetics4j/core/chromosomes/TreeNode::hashCode → NO_COVERAGE |
return result; |
| 228 | } | |
| 229 | ||
| 230 | @Override | |
| 231 | public boolean equals(Object obj) { | |
| 232 |
2
1. equals : removed conditional - replaced equality check with true → SURVIVED 2. equals : negated conditional → SURVIVED |
if (this == obj) |
| 233 |
2
1. equals : replaced boolean return with false for net/bmahe/genetics4j/core/chromosomes/TreeNode::equals → KILLED 2. equals : Substituted 1 with 0 → KILLED |
return true; |
| 234 |
3
1. equals : removed conditional - replaced equality check with false → NO_COVERAGE 2. equals : negated conditional → NO_COVERAGE 3. equals : removed conditional - replaced equality check with true → NO_COVERAGE |
if (obj == null) |
| 235 |
2
1. equals : replaced boolean return with true for net/bmahe/genetics4j/core/chromosomes/TreeNode::equals → NO_COVERAGE 2. equals : Substituted 0 with 1 → NO_COVERAGE |
return false; |
| 236 |
5
1. equals : removed conditional - replaced equality check with false → NO_COVERAGE 2. equals : negated conditional → NO_COVERAGE 3. equals : removed conditional - replaced equality check with true → NO_COVERAGE 4. equals : removed call to java/lang/Object::getClass → NO_COVERAGE 5. equals : removed call to java/lang/Object::getClass → NO_COVERAGE |
if (getClass() != obj.getClass()) |
| 237 |
2
1. equals : Substituted 0 with 1 → NO_COVERAGE 2. equals : replaced boolean return with true for net/bmahe/genetics4j/core/chromosomes/TreeNode::equals → NO_COVERAGE |
return false; |
| 238 | TreeNode other = (TreeNode) obj; | |
| 239 |
3
1. equals : removed conditional - replaced equality check with false → NO_COVERAGE 2. equals : removed conditional - replaced equality check with true → NO_COVERAGE 3. equals : negated conditional → NO_COVERAGE |
if (data == null) { |
| 240 |
3
1. equals : negated conditional → NO_COVERAGE 2. equals : removed conditional - replaced equality check with true → NO_COVERAGE 3. equals : removed conditional - replaced equality check with false → NO_COVERAGE |
if (other.data != null) |
| 241 |
2
1. equals : replaced boolean return with true for net/bmahe/genetics4j/core/chromosomes/TreeNode::equals → NO_COVERAGE 2. equals : Substituted 0 with 1 → NO_COVERAGE |
return false; |
| 242 |
4
1. equals : removed conditional - replaced equality check with true → NO_COVERAGE 2. equals : negated conditional → NO_COVERAGE 3. equals : removed call to java/lang/Object::equals → NO_COVERAGE 4. equals : removed conditional - replaced equality check with false → NO_COVERAGE |
} else if (!data.equals(other.data)) |
| 243 |
2
1. equals : Substituted 0 with 1 → NO_COVERAGE 2. equals : replaced boolean return with true for net/bmahe/genetics4j/core/chromosomes/TreeNode::equals → NO_COVERAGE |
return false; |
| 244 |
3
1. equals : removed conditional - replaced equality check with false → NO_COVERAGE 2. equals : negated conditional → NO_COVERAGE 3. equals : removed conditional - replaced equality check with true → NO_COVERAGE |
if (children == null) { |
| 245 |
3
1. equals : removed conditional - replaced equality check with false → NO_COVERAGE 2. equals : removed conditional - replaced equality check with true → NO_COVERAGE 3. equals : negated conditional → NO_COVERAGE |
if (other.children != null) |
| 246 |
2
1. equals : Substituted 0 with 1 → NO_COVERAGE 2. equals : replaced boolean return with true for net/bmahe/genetics4j/core/chromosomes/TreeNode::equals → NO_COVERAGE |
return false; |
| 247 |
4
1. equals : negated conditional → NO_COVERAGE 2. equals : removed conditional - replaced equality check with true → NO_COVERAGE 3. equals : removed call to java/util/ArrayList::equals → NO_COVERAGE 4. equals : removed conditional - replaced equality check with false → NO_COVERAGE |
} else if (!children.equals(other.children)) |
| 248 |
2
1. equals : replaced boolean return with true for net/bmahe/genetics4j/core/chromosomes/TreeNode::equals → NO_COVERAGE 2. equals : Substituted 0 with 1 → NO_COVERAGE |
return false; |
| 249 | ||
| 250 |
2
1. equals : replaced boolean return with false for net/bmahe/genetics4j/core/chromosomes/TreeNode::equals → NO_COVERAGE 2. equals : Substituted 1 with 0 → NO_COVERAGE |
return true; |
| 251 | } | |
| 252 | ||
| 253 | @Override | |
| 254 | public String toString() { | |
| 255 |
3
1. toString : replaced return value with "" for net/bmahe/genetics4j/core/chromosomes/TreeNode::toString → NO_COVERAGE 2. toString : removed call to java/lang/String::valueOf → NO_COVERAGE 3. toString : removed call to java/lang/String::valueOf → NO_COVERAGE |
return "TreeNode [data=" + data + ", children=" + children + "]"; |
| 256 | } | |
| 257 | ||
| 258 | /** | |
| 259 | * Creates a new tree node with the specified data and children. | |
| 260 | * | |
| 261 | * <p>This factory method provides a convenient way to construct trees with a specific structure in a single | |
| 262 | * operation. All provided children are added to the new node. | |
| 263 | * | |
| 264 | * @param <U> the type of data stored in the nodes | |
| 265 | * @param data the data to store in the root node | |
| 266 | * @param children the collection of child nodes to add | |
| 267 | * @return a new tree node with the specified data and children | |
| 268 | * @throws IllegalArgumentException if data is null, children is null, or children is empty | |
| 269 | */ | |
| 270 | public static <U> TreeNode<U> of(final U data, final Collection<TreeNode<U>> children) { | |
| 271 | Validate.notNull(data); | |
| 272 | Validate.notNull(children); | |
| 273 | Validate.isTrue(children.size() > 0); | |
| 274 | ||
| 275 |
1
1. of : removed call to net/bmahe/genetics4j/core/chromosomes/TreeNode::<init> → KILLED |
final TreeNode<U> rootNode = new TreeNode<>(data); |
| 276 | for (TreeNode<U> childNode : children) { | |
| 277 |
1
1. of : removed call to net/bmahe/genetics4j/core/chromosomes/TreeNode::addChild → KILLED |
rootNode.addChild(childNode); |
| 278 | } | |
| 279 | ||
| 280 |
1
1. of : replaced return value with null for net/bmahe/genetics4j/core/chromosomes/TreeNode::of → KILLED |
return rootNode; |
| 281 | } | |
| 282 | } | |
Mutations | ||
| 105 |
1.1 |
|
| 106 |
1.1 2.2 |
|
| 115 |
1.1 |
|
| 127 |
1.1 |
|
| 141 |
1.1 2.2 |
|
| 158 |
1.1 2.2 |
|
| 173 |
1.1 |
|
| 189 |
1.1 |
|
| 201 |
1.1 2.2 3.3 |
|
| 202 |
1.1 2.2 |
|
| 203 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
| 215 |
1.1 2.2 3.3 |
|
| 216 |
1.1 2.2 |
|
| 217 |
1.1 2.2 3.3 |
|
| 218 |
1.1 2.2 3.3 4.4 5.5 |
|
| 223 |
1.1 |
|
| 224 |
1.1 |
|
| 225 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 226 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 227 |
1.1 |
|
| 232 |
1.1 2.2 |
|
| 233 |
1.1 2.2 |
|
| 234 |
1.1 2.2 3.3 |
|
| 235 |
1.1 2.2 |
|
| 236 |
1.1 2.2 3.3 4.4 5.5 |
|
| 237 |
1.1 2.2 |
|
| 239 |
1.1 2.2 3.3 |
|
| 240 |
1.1 2.2 3.3 |
|
| 241 |
1.1 2.2 |
|
| 242 |
1.1 2.2 3.3 4.4 |
|
| 243 |
1.1 2.2 |
|
| 244 |
1.1 2.2 3.3 |
|
| 245 |
1.1 2.2 3.3 |
|
| 246 |
1.1 2.2 |
|
| 247 |
1.1 2.2 3.3 4.4 |
|
| 248 |
1.1 2.2 |
|
| 250 |
1.1 2.2 |
|
| 255 |
1.1 2.2 3.3 |
|
| 275 |
1.1 |
|
| 277 |
1.1 |
|
| 280 |
1.1 |