/// <summary> /// Post-order tree traversal method. /// </summary> /// /// <remarks> /// Adapted from John Cowan (1998) recommendation. /// </remarks> /// public static IEnumerator <DecisionNode> PostOrder(DecisionNode tree) { var cursor = new Dictionary <DecisionNode, int>(); DecisionNode currentNode = tree; while (currentNode != null) { // Move down to first child DecisionNode nextNode = null; if (currentNode.Branches != null) { nextNode = currentNode.Branches.FirstOrDefault(); } if (nextNode != null) { currentNode = nextNode; continue; } // No child nodes, so walk tree while (currentNode != null) { yield return(currentNode); // post order // Move to sibling if possible. nextNode = GetNextSibling(cursor, currentNode); if (nextNode != null) { currentNode = nextNode; break; } // Move up if (currentNode == nextNode) { currentNode = null; } else { currentNode = currentNode.Parent; } } } }
private void create(DecisionNode node, int depth) { string indent = new string(' ', depth * 4); if (!node.IsLeaf) { int attributeIndex = node.Branches.AttributeIndex; // Create all comparison expressions for (int i = 0; i < node.Branches.Count; i++) { DecisionNode child = node.Branches[i]; string cmp = ComparisonExtensions.ToString(child.Comparison); if (i == 0) { writer.Write(indent + "if "); } else { writer.Write(indent + "else if "); } writer.Write("(input[{0}] {1} {2}) {{", attributeIndex, cmp, child.Value); writer.WriteLine(); create(child, depth + 1); writer.WriteLine(indent + "}"); } writer.WriteLine(indent + "else throw new ArgumentException(\"input\", \"Unexpected value at position " + attributeIndex + ".\");"); } else // node is a leaf { if (node.Output.HasValue) { writer.WriteLine(indent + "return " + node.Output.Value + ";"); } else { writer.WriteLine(indent + "return -1;"); } } }
/// <summary> /// Depth-first traversal method. /// </summary> /// public static IEnumerator <DecisionNode> DepthFirst(DecisionNode tree) { if (tree == null) { yield break; } var stack = new Stack <DecisionNode>(new[] { tree }); while (stack.Count != 0) { DecisionNode current = stack.Pop(); yield return(current); if (current.Branches != null) { for (int i = current.Branches.Count - 1; i >= 0; i--) { stack.Push(current.Branches[i]); } } } }
/// <summary> /// Breadth-first traversal method. /// </summary> /// public static IEnumerator <DecisionNode> BreadthFirst(DecisionNode tree) { if (tree == null) { yield break; } var queue = new Queue <DecisionNode>(new[] { tree }); while (queue.Count != 0) { DecisionNode current = queue.Dequeue(); yield return(current); if (current.Branches != null) { foreach (var child in current.Branches) { queue.Enqueue(child); } } } }
internal static DecisionNode GetNextSibling(Dictionary <DecisionNode, int> cursors, DecisionNode node) { var parent = node.Parent; if (parent == null) { return(null); } // Get current node index int index; if (!cursors.TryGetValue(node, out index)) { cursors[node] = index = 0; } int nextIndex = index + 1; if (nextIndex < parent.Branches.Count) { var sibling = parent.Branches[nextIndex]; cursors[sibling] = nextIndex; return(sibling); } return(null); }
private Expression create(DecisionNode node) { if (!node.IsLeaf) { int attributeIndex = node.Branches.AttributeIndex; // Create all comparison expressions BinaryExpression[] comparisons = new BinaryExpression[node.Branches.Count]; Expression[] childExpression = new Expression[node.Branches.Count]; for (int i = 0; i < comparisons.Length; i++) { DecisionNode child = node.Branches[i]; var expr = Expression.ArrayIndex(inputs, Expression.Constant(attributeIndex)); var cons = Expression.Constant(child.Value); switch (child.Comparison) { case ComparisonKind.Equal: comparisons[i] = Expression.Equal(expr, cons); break; case ComparisonKind.GreaterThan: comparisons[i] = Expression.GreaterThan(expr, cons); break; case ComparisonKind.GreaterThanOrEqual: comparisons[i] = Expression.GreaterThanOrEqual(expr, cons); break; case ComparisonKind.LessThan: comparisons[i] = Expression.LessThan(expr, cons); break; case ComparisonKind.LessThanOrEqual: comparisons[i] = Expression.LessThanOrEqual(expr, cons); break; case ComparisonKind.NotEqual: comparisons[i] = Expression.NotEqual(expr, cons); break; default: throw new InvalidOperationException("Unexpected node comparison type."); } childExpression[i] = create(node.Branches[i]); } // Create expression for else expressions ConstructorInfo ex = typeof(ArgumentException).GetConstructor(new[] { typeof(string), typeof(string) }); var lastElse = Expression.IfThenElse(comparisons[comparisons.Length - 1], childExpression[comparisons.Length - 1], Expression.Throw(Expression.New(ex, Expression.Constant("Input contains a value outside of expected ranges."), Expression.Constant("input")))); ConditionalExpression currentIf = null; for (int i = comparisons.Length - 2; i >= 0; i--) { currentIf = Expression.IfThenElse(comparisons[i], childExpression[i], lastElse); lastElse = currentIf; } return(currentIf); } else // node is a leaf { if (node.Output.HasValue) { return(Expression.Return(label, Expression.Constant(node.Output.Value), typeof(int))); } return(Expression.Return(label, Expression.Constant(-1), typeof(int))); } }