1 package net.bmahe.genetics4j.core.chromosomes;
2
3 import java.util.Objects;
4
5 /**
6 * A chromosome implementation that represents genetic information as a tree structure.
7 *
8 * <p>TreeChromosome is essential for genetic programming and other evolutionary approaches that require hierarchical or
9 * nested representations. The tree structure allows for variable-length solutions and naturally supports recursive data
10 * types and operations.
11 *
12 * <p>This chromosome type is particularly suitable for:
13 * <ul>
14 * <li><strong>Genetic Programming</strong>: Evolving mathematical expressions, programs, and functions</li>
15 * <li><strong>Decision trees</strong>: Classification and regression tree learning</li>
16 * <li><strong>Parse trees</strong>: Grammar evolution and language processing</li>
17 * <li><strong>Hierarchical structures</strong>: Neural network topologies, circuit designs</li>
18 * <li><strong>Symbolic regression</strong>: Finding mathematical models that fit data</li>
19 * <li><strong>Rule evolution</strong>: Evolving conditional logic and decision rules</li>
20 * </ul>
21 *
22 * <p>Key characteristics:
23 * <ul>
24 * <li><strong>Variable structure</strong>: Tree depth and branching can vary between individuals</li>
25 * <li><strong>Hierarchical representation</strong>: Natural support for nested and recursive structures</li>
26 * <li><strong>Type-safe nodes</strong>: Generic type parameter ensures consistent node data types</li>
27 * <li><strong>Immutable backbone</strong>: Tree structure is fixed after construction</li>
28 * </ul>
29 *
30 * <p>The chromosome contains a single root node that represents the entire tree structure. The tree size (total number
31 * of nodes) is calculated recursively from the root node. For the purpose of the Chromosome interface, this counts as
32 * one "allele" since it represents a single cohesive genetic unit.
33 *
34 * <p>Tree genetic operators typically work by:
35 * <ul>
36 * <li><strong>Crossover</strong>: Exchanging subtrees between parent chromosomes</li>
37 * <li><strong>Mutation</strong>: Replacing subtrees or individual nodes</li>
38 * <li><strong>Growth/Pruning</strong>: Adding or removing branches to control complexity</li>
39 * </ul>
40 *
41 * @param <T> the type of data stored in tree nodes
42 * @see TreeNode
43 * @see Chromosome
44 * @see TreeNode
45 */
46 public class TreeChromosome<T> implements Chromosome {
47
48 private final TreeNode<T> root;
49
50 /**
51 * Creates a new tree chromosome with the specified root node.
52 *
53 * @param _root the root node of the tree structure
54 * @throws IllegalArgumentException if root is null
55 */
56 public TreeChromosome(final TreeNode<T> _root) {
57 Objects.requireNonNull(_root);
58
59 this.root = _root;
60 }
61
62 /**
63 * Returns the number of alleles in this chromosome.
64 *
65 * <p>For tree chromosomes, this always returns 1 since the entire tree is considered a single genetic unit (allele).
66 * To get the total number of nodes in the tree, use {@link #getSize()}.
67 *
68 * @return 1, representing the tree as a single allele
69 */
70 @Override
71 public int getNumAlleles() {
72 return 1;
73 }
74
75 /**
76 * Returns the root node of this tree chromosome.
77 *
78 * @return the root node containing the entire tree structure
79 */
80 public TreeNode<T> getRoot() {
81 return root;
82 }
83
84 /**
85 * Returns the total number of nodes in the tree.
86 *
87 * <p>This method recursively counts all nodes in the tree starting from the root node, including internal nodes and
88 * leaves.
89 *
90 * @return the total number of nodes in the tree
91 */
92 public int getSize() {
93 return root.getSize();
94 }
95
96 @Override
97 public int hashCode() {
98 final int prime = 31;
99 int result = 1;
100 return prime * result + (root == null ? 0 : root.hashCode());
101 }
102
103 @Override
104 public boolean equals(Object obj) {
105 if (this == obj) {
106 return true;
107 }
108 if (obj == null) {
109 return false;
110 }
111 if (getClass() != obj.getClass()) {
112 return false;
113 }
114 TreeChromosome other = (TreeChromosome) obj;
115 if (root == null) {
116 if (other.root != null) {
117 return false;
118 }
119 } else if (!root.equals(other.root)) {
120 return false;
121 }
122 return true;
123 }
124
125 @Override
126 public String toString() {
127 return "TreeChromosome [root=" + root + "]";
128 }
129 }