/// <summary> /// Clone the tree node. /// </summary> /// /// <returns>Returns exact clone of the node.</returns> /// public object Clone( ) { GPTreeNode clone = new GPTreeNode( ); // clone gene clone.Gene = this.Gene.Clone( ); // clone its children if ( this.Children != null ) { clone.Children = new List<GPTreeNode>( ); // clone each child gene foreach ( GPTreeNode node in Children ) { clone.Children.Add( (GPTreeNode) node.Clone( ) ); } } return clone; }
/// <summary> /// Initializes a new instance of the <see cref="GPTreeChromosome"/> class. /// </summary> /// /// <param name="source">Source genetic tree to clone from.</param> /// /// <remarks><para>This constructor creates new genetic tree as a copy of the /// specified <paramref name="source"/> tree.</para></remarks> /// protected GPTreeChromosome( GPTreeChromosome source ) { root = (GPTreeNode) source.root.Clone( ); fitness = source.fitness; }
/// <summary> /// Trim tree node, so its depth does not exceed specified level. /// </summary> private static void Trim( GPTreeNode node, int level ) { // check if the node has children if ( node.Children != null ) { if ( level == 0 ) { // remove all children node.Children = null; // and make the node of argument type node.Gene.Generate( GPGeneType.Argument ); } else { // go further to children foreach ( GPTreeNode n in node.Children ) { Trim( n, level - 1 ); } } } }
/// <summary> /// Crossover helper routine - selects random node of chromosomes tree and /// swaps it with specified node. /// </summary> private GPTreeNode RandomSwap( GPTreeNode source ) { GPTreeNode retNode = null; // swap root node ? if ( ( root.Children == null ) || ( rand.Next( maxLevel ) == 0 ) ) { // replace current root and return it retNode = root; root = source; } else { GPTreeNode node = root; for ( ; ; ) { // choose random child int r = rand.Next( node.Gene.ArgumentsCount ); GPTreeNode child = (GPTreeNode) node.Children[r]; // swap the random node, if it is an end node or // random generator "selected" this node if ( ( child.Children == null ) || ( rand.Next( maxLevel ) == 0 ) ) { // swap the node with pair's one retNode = child; node.Children[r] = source; break; } // go further by tree node = child; } } return retNode; }
/// <summary> /// Generate chromosome's subtree of specified level. /// </summary> /// /// <param name="node">Sub tree's node to generate.</param> /// <param name="level">Sub tree's level to generate.</param> /// protected void Generate( GPTreeNode node, int level ) { // create gene for the node if ( level == 0 ) { // the gene should be an argument node.Gene = root.Gene.CreateNew( GPGeneType.Argument ); } else { // the gene can be function or argument node.Gene = root.Gene.CreateNew( ); } // add children if ( node.Gene.ArgumentsCount != 0 ) { node.Children = new List<GPTreeNode>( ); for ( int i = 0; i < node.Gene.ArgumentsCount; i++ ) { // create new child GPTreeNode child = new GPTreeNode( ); Generate( child, level - 1 ); // add the new child node.Children.Add( child ); } } }
/// <summary> /// Mutation operator. /// </summary> /// /// <remarks><para>The method performs chromosome's mutation by regenerating tree's /// randomly selected node.</para></remarks> /// public override void Mutate( ) { // current tree level int currentLevel = 0; // current node GPTreeNode node = root; for ( ; ; ) { // regenerate node if it does not have children if ( node.Children == null ) { if ( currentLevel == maxLevel ) { // we reached maximum possible level, so the gene // can be an argument only node.Gene.Generate( GPGeneType.Argument ); } else { // generate subtree Generate( node, rand.Next( maxLevel - currentLevel ) ); } break; } // if it is a function node, than we need to get a decision, about // mutation point - the node itself or one of its children int r = rand.Next( node.Gene.ArgumentsCount + 1 ); if ( r == node.Gene.ArgumentsCount ) { // node itself should be regenerated node.Gene.Generate( ); // check current type if ( node.Gene.GeneType == GPGeneType.Argument ) { node.Children = null; } else { // create children's list if it was absent if ( node.Children == null ) node.Children = new List<GPTreeNode>( ); // check for missing or extra children if ( node.Children.Count != node.Gene.ArgumentsCount ) { if ( node.Children.Count > node.Gene.ArgumentsCount ) { // remove extra children node.Children.RemoveRange( node.Gene.ArgumentsCount, node.Children.Count - node.Gene.ArgumentsCount ); } else { // add missing children for ( int i = node.Children.Count; i < node.Gene.ArgumentsCount; i++ ) { // create new child GPTreeNode child = new GPTreeNode( ); Generate( child, rand.Next( maxLevel - currentLevel ) ); // add the new child node.Children.Add( child ); } } } } break; } // mutation goes further to one of the children node = (GPTreeNode) node.Children[r]; currentLevel++; } }
/// <summary> /// Generate random chromosome value. /// </summary> /// /// <remarks><para>Regenerates chromosome's value using random number generator.</para> /// </remarks> /// public override void Generate( ) { // randomize the root root.Gene.Generate( ); // create children if ( root.Gene.ArgumentsCount != 0 ) { root.Children = new List<GPTreeNode>( ); for ( int i = 0; i < root.Gene.ArgumentsCount; i++ ) { // create new child GPTreeNode child = new GPTreeNode( ); Generate( child, rand.Next( maxInitialLevel ) ); // add the new child root.Children.Add( child ); } } }
/// <summary> /// Crossover operator. /// </summary> /// /// <param name="pair">Pair chromosome to crossover with.</param> /// /// <remarks><para>The method performs crossover between two chromosomes – interchanging /// randomly selected sub trees.</para></remarks> /// public override void Crossover( IChromosome pair ) { GPTreeChromosome p = (GPTreeChromosome) pair; // check for correct pair if ( p != null ) { // do we need to use root node for crossover ? if ( ( root.Children == null ) || ( rand.Next( maxLevel ) == 0 ) ) { // give the root to the pair and use pair's part as a new root root = p.RandomSwap( root ); } else { GPTreeNode node = root; for ( ; ; ) { // choose random child int r = rand.Next( node.Gene.ArgumentsCount ); GPTreeNode child = (GPTreeNode) node.Children[r]; // swap the random node, if it is an end node or // random generator "selected" this node if ( ( child.Children == null ) || ( rand.Next( maxLevel ) == 0 ) ) { // swap the node with pair's one node.Children[r] = p.RandomSwap( child ); break; } // go further by tree node = child; } } // trim both of them Trim( root, maxLevel ); Trim( p.root, maxLevel ); } }
/// <summary> /// Get tree representation of the chromosome. /// </summary> /// /// <returns>Returns expression's tree represented by the chromosome.</returns> /// /// <remarks><para>The method builds expression's tree for the native linear representation /// of the GEP chromosome.</para></remarks> /// protected GPTreeNode GetTree( ) { // function node queue. the queue contains function node, // which requires children. when a function node receives // all children, it will be removed from the queue Queue functionNodes = new Queue( ); // create root node GPTreeNode root = new GPTreeNode( genes[0] ); // check children amount of the root node if ( root.Gene.ArgumentsCount != 0 ) { root.Children = new List<GPTreeNode>( ); // place the root to the queue functionNodes.Enqueue( root ); // go through genes for ( int i = 1; i < length; i++ ) { // create new node GPTreeNode node = new GPTreeNode( genes[i] ); // if next gene represents function, place it to the queue if ( genes[i].GeneType == GPGeneType.Function ) { node.Children = new List<GPTreeNode>( ); functionNodes.Enqueue( node ); } // get function node from the top of the queue GPTreeNode parent = (GPTreeNode) functionNodes.Peek( ); // add new node to children of the parent node parent.Children.Add( node ); // remove the parent node from the queue, if it is // already complete if ( parent.Children.Count == parent.Gene.ArgumentsCount ) { functionNodes.Dequeue( ); // check the queue if it is empty if ( functionNodes.Count == 0 ) break; } } } // return formed tree return root; }