View Javadoc
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 }