/// <summary> /// Compare two nodes. /// </summary> /// <param name="result">The result of previous comparisons.</param> /// <param name="node1">The first node to compare.</param> /// <param name="node2">The second node to compare.</param> /// <returns>The result.</returns> private double CompareNode(double result, TreeGenomeNode node1, TreeGenomeNode node2) { double newResult = result; int node1Size = node1.Children.Count; int node2Size = node2.Children.Count; int childNodeCount = Math.Max(node1Size, node2Size); for (int i = 0; i < childNodeCount; i++) { if (i < node1Size && i < node2Size) { TreeGenomeNode childNode1 = node1.Children[i]; TreeGenomeNode childNode2 = node2.Children[i]; newResult = CompareNode(newResult, childNode1, childNode2); } else { newResult++; } } return newResult; }
/// <summary> /// Grow the tree randomly by the specified max depth. /// </summary> /// <param name="rnd">A random number generator.</param> /// <param name="maxDepth">The max depth.</param> /// <returns>The tree.</returns> public TreeGenomeNode Grow(IGenerateRandom rnd, int maxDepth) { if (maxDepth == 1) { return(new TreeGenomeNode(ChooseRandomLeafOpcode(rnd))); } var result = new TreeGenomeNode(ChooseRandomNodeOpcode(rnd)); int childCount = DetermineChildCount(result.Opcode); for (int i = 0; i < childCount; i++) { result.Children.Add(Grow(rnd, maxDepth - 1)); } return(result); }
/// <summary> /// /// </summary> /// <param name="rnd"></param> /// <param name="parent"></param> /// <param name="current"></param> /// <param name="index"></param> /// <param name="reservoir"></param> private void InternalSampleRandomNode(IGenerateRandom rnd, TreeGenomeNode parent, TreeGenomeNode current, int[] index, RandomNodeResult reservoir) { int currentIndex = index[0]; index[0]++; // determine if we replace the reservoir int j = rnd.NextInt(0, currentIndex + 1); if (j == 0) { reservoir.Parent = parent; reservoir.Child = current; } // traverse on to the children foreach (TreeGenomeNode child in current.Children) { InternalSampleRandomNode(rnd, current, child, index, reservoir); } }
/// <inheritdoc /> public void PerformOperation(IGenerateRandom rnd, IGenome[] parents, int parentIndex, IGenome[] offspring, int offspringIndex) { var parent1 = (TreeGenome)parents[parentIndex]; EvaluateTree eval = parent1.Evaluator; var off1 = (TreeGenome)_owner.Population.GenomeFactory.Factor(parent1); RandomNodeResult off1Point = eval.SampleRandomNode(rnd, off1.Root); int len = rnd.NextInt(1, _maxGraftLength + 1); TreeGenomeNode randomSequence = eval.Grow(rnd, len); if (off1Point.Parent == null) { off1.Root = randomSequence; } else { int idx = off1Point.Parent.Children.IndexOf(off1Point.Child); off1Point.Parent.Children[idx] = randomSequence; } offspring[0] = off1; }
/// <summary> /// Create a copy of this node. /// </summary> /// <returns>A copy (clone) of this node.</returns> public TreeGenomeNode Copy() { var result = new TreeGenomeNode(_opcode); foreach (TreeGenomeNode child in _children) { result.Children.Add(child.Copy()); } return result; }
/// <summary> /// Evaluate the specified node. /// </summary> /// <param name="node">The node to evaluate.</param> /// <param name="varValues">The variable values.</param> /// <returns>The result of the evaluation.</returns> public abstract double Evaluate(TreeGenomeNode node, double[] varValues);
/// <summary> /// Grow the tree randomly by the specified max depth. /// </summary> /// <param name="rnd">A random number generator.</param> /// <param name="maxDepth">The max depth.</param> /// <returns>The tree.</returns> public TreeGenomeNode Grow(IGenerateRandom rnd, int maxDepth) { if (maxDepth == 1) { return new TreeGenomeNode(ChooseRandomLeafOpcode(rnd)); } var result = new TreeGenomeNode(ChooseRandomNodeOpcode(rnd)); int childCount = DetermineChildCount(result.Opcode); for (int i = 0; i < childCount; i++) { result.Children.Add(Grow(rnd, maxDepth - 1)); } return result; }
/// <summary> /// Choose a random node from the tree. Uses reservoir sampling. /// </summary> /// <param name="rnd">Random number generator.</param> /// <param name="root">The root of the tree.</param> /// <returns>A random node.</returns> public RandomNodeResult SampleRandomNode(IGenerateRandom rnd, TreeGenomeNode root) { var index = new int[1]; var reservoir = new RandomNodeResult(); index[0] = 0; InternalSampleRandomNode(rnd, null, root, index, reservoir); return reservoir; }
/// <inheritdoc /> public override double Evaluate(TreeGenomeNode node, double[] varValues) { switch (node.Opcode) { case OPCODE_NEG: return -(Evaluate(node.Children[0], varValues)); case OPCODE_ADD: return Evaluate(node.Children[0], varValues) + Evaluate(node.Children[1], varValues); case OPCODE_SUB: return Evaluate(node.Children[0], varValues) - Evaluate(node.Children[1], varValues); case OPCODE_DIV: return Evaluate(node.Children[0], varValues) / Evaluate(node.Children[1], varValues); case OPCODE_MUL: return Evaluate(node.Children[0], varValues) * Evaluate(node.Children[1], varValues); case OPCODE_POWER: return Math.Pow(Evaluate(node.Children[0], varValues), Evaluate(node.Children[1], varValues)); case OPCODE_SQRT: return Math.Sqrt(Evaluate(node.Children[0], varValues)); default: int index = node.Opcode - OPCODE_VAR_CONST; if (index >= (constValues.Length + varCount)) { throw new AIFHError("Invalid opcode: " + node.Opcode); } if (index < varCount) { return varValues[index]; } return constValues[index - varCount]; } }
/// <summary> /// Display an expression as normal infix. /// </summary> /// <param name="node">The root node.</param> /// <returns>The infix string.</returns> public String DisplayExpressionNormal(TreeGenomeNode node) { var result = new StringBuilder(); if (DetermineChildCount(node.Opcode) == 0) { result.Append(GetOpcodeText(node.Opcode)); } else { int childCount = DetermineChildCount(node.Opcode); if (childCount == 0) { result.Append(GetOpcodeText(node.Opcode)); } else { String name = GetOpcodeText(node.Opcode); if (name.Length > 1) { result.Append(name); result.Append("("); bool first = true; foreach (TreeGenomeNode child in node.Children) { if (!first) { result.Append(","); } result.Append(DisplayExpressionNormal(child)); first = false; } result.Append(")"); } else { result.Append("("); if (childCount == 2) { result.Append(DisplayExpressionNormal(node.Children[0])); result.Append(name); result.Append(DisplayExpressionNormal(node.Children[1])); result.Append(")"); } else { result.Append(name); result.Append(DisplayExpressionNormal(node.Children[0])); result.Append(")"); } } } } return result.ToString(); }
/// <summary> /// Display an expression as LISP (the programming language) /// </summary> /// <param name="node">The root node.</param> /// <returns>The LISP for the expression.</returns> public String DisplayExpressionLISP(TreeGenomeNode node) { var result = new StringBuilder(); if (DetermineChildCount(node.Opcode) == 0) { result.Append(GetOpcodeText(node.Opcode)); } else { result.Append("("); result.Append(GetOpcodeText(node.Opcode)); foreach (TreeGenomeNode child in node.Children) { result.Append(" "); result.Append(DisplayExpressionLISP(child)); } result.Append(")"); } return result.ToString(); }