private TreeEvalItem <TTreeNode> GetNextRBFSCousin(TTreeNode curr, TreeNodePath path, int targetDepth) { // If we've gotten into an error state, or if we're attempting to go past root if (curr == null || curr == m_traversalParameters.Root) { return(null); } // Iterate over all siblings and build a stack of siblings for us to evaluate (popping will give us sibling closest to curr, instead of parent's index[0]) var parent = m_traversalParameters.GetParentMethod(curr); if (parent == null) { return(null); } var siblingStack = new Stack <IndexTrackedNode>(); int siblingIndex = 0; foreach (var sibling in m_traversalParameters.GetChildrenMethod(parent)) { if (sibling == curr) { break; } siblingStack.Push(new IndexTrackedNode(siblingIndex++, sibling)); } // Evaluate from closest to curr back to index zero, and call GetlastLeafAtDepth, if we find a cousin at the target depth // then that is the next BFS item to search while (siblingStack.Count > 0) { var next = siblingStack.Pop(); TreeEvalItem <TTreeNode> cousinLeaf = this.GetLastLeafAtDepth(next.Node, path.CopyAndSwapEndForSibling(next.Index), targetDepth); if (cousinLeaf != null) { return(cousinLeaf); } } // If no cousin is found, than recurse upwards, this will be evaluting parent as curr return(this.GetNextRBFSCousin(parent, path.CopyAndRemoveEnd(), targetDepth)); }
private TreeEvalItem <TTreeNode> GetLastLeafAtDepth(TTreeNode node, TreeNodePath path, int targetDepth) { if (path.Count == targetDepth) { return(new TreeEvalItem <TTreeNode>(node, path)); } List <TTreeNode> children = m_traversalParameters.GetChildrenMethod(node).ToList(); for (int childIndex = children.Count - 1; childIndex >= 0; --childIndex) { var result = GetLastLeafAtDepth(children[childIndex], path.CopyAndAddToPath(childIndex), targetDepth); if (result != null) { return(result); } } return(null); }
/// <summary> /// Specialty constructor for creating iter from a root node /// </summary> /// <param name="start">The root node</param> /// <param name="traversalParameters">The parameters to the tree traversal</param> /// <param name="getChildrenMethodOverride">An override to the default GetChildren method</param> /// <param name="getParentMethodOverride">An override to the default GetParent method</param> internal TreeIter(TTreeNode start, TreeTraversalParameters <TTreeNode> traversalParameters) { this.TraversalParameters = traversalParameters; // We want our paths to be root-centric so if start is not root (and there is a root listed) // then we need to give ourselves a starter path from root TreeNodePath pathFromRoot = null; if (traversalParameters.Root != null && start != traversalParameters.Root) { var treePath = new Stack <int>(); TTreeNode target = start; while (target != null && target != traversalParameters.Root) { var parent = this.TraversalParameters.GetParentMethod(target); if (parent == null) { break; } // To path in this way, we must gurantee that the children we get are indexable // thus this will throw if they are not of IList var children = this.TraversalParameters.GetChildrenMethod.Invoke(parent); if (children is IList listChild) { treePath.Push(listChild.IndexOf(target)); } else { treePath.Push(children.Count(_ => _ != target)); } target = parent; } pathFromRoot = new TreeNodePath(treePath); } this.State = new TreeIterState <TTreeNode>(start, traversalParameters, pathFromRoot); this.State.ProcessNextEvaluations(); }
private void ProcessNextEvaluationsForParentTraversal() { TTreeNode parent = this.Target != null?m_traversalParameters.GetParentMethod(this.Target) : null; if (parent == null) { return; } if (!this.IsUniqueInIteration(parent)) { return; } TreeNodePath newPath = this.TargetPath.CopyAndRemoveEnd(); m_nextEvalSet.Add(new TreeEvalItem <TTreeNode>(parent, newPath)); if (m_traversalParameters.TrackReentrancy) { m_reentrancyTracking.Add(parent); } return; }
public static int CompareTreeNodePaths(TreeNodePath left, TreeNodePath right, eTraversalFlowDirection flowDirection = eTraversalFlowDirection.ThroughChildren, eTraversalStrategy traversalStrategy = eTraversalStrategy.Default) { switch (flowDirection) { case eTraversalFlowDirection.ThroughParents: return(CompareTreeNodePaths_ThroughParents(left, right)); case eTraversalFlowDirection.ThroughChildren: if (traversalStrategy == eTraversalStrategy.BreadthFirst) { return(CompareTreeNodePaths_BreadthFirst(left, right)); } return(CompareTreeNodePaths_DepthFirst(left, right)); case eTraversalFlowDirection.ReversedThroughChildren: if (traversalStrategy == eTraversalStrategy.BreadthFirst) { return(CompareTreeNodePaths_ReverseBreadthFirst(left, right)); } return(CompareTreeNodePaths_ReverseDepthFirst(left, right)); } throw new InvalidOperationException("Traversal flow and/or strategy was invalid, flowDirection was casted to something invalid"); }
private TreeEvalItem <TTreeNode> ProcessNextEvaluationsForRBFS(TTreeNode target, TreeNodePath path, int targetDepth) { if (target == null) { return(null); } var parent = m_traversalParameters.GetParentMethod(target); if (parent == null) { return(null); } TTreeNode nextClosestSibling = null; int nextClosestSiblingIndex = -1; int childIndex = 0; foreach (var sibling in m_traversalParameters.GetChildrenMethod(parent)) { if (sibling == target) { break; } nextClosestSiblingIndex = childIndex++; nextClosestSibling = sibling; } // No siblings, recurse to the parent/grandparent if (nextClosestSibling == null) { TreeEvalItem <TTreeNode> cousin = this.GetNextRBFSCousin(parent, path.CopyAndRemoveEnd(), targetDepth); if (cousin != null) { return(cousin); } // Looks like end of this depth... time to go forward and back to the end return(this.GetLastLeafAtDepth(m_traversalParameters.Root, new TreeNodePath(), this.CurrentDepthFromOrigin - 1)); } // There were some siblings, see if we can find our next target return(new TreeEvalItem <TTreeNode>(nextClosestSibling, path.CopyAndSwapEndForSibling(nextClosestSiblingIndex))); }
private TreeEvalItem <TTreeNode> GetLastLeaf(TTreeNode node, int currentDepth, TreeNodePath path) { IList <TTreeNode> children = m_traversalParameters.GetChildrenMethod(node).ToList(); if (children.Count == 0) { return(new TreeEvalItem <TTreeNode>(node, path)); } int lastIndex = children.Count - 1; path.AddToPath(lastIndex); return(GetLastLeaf(children[lastIndex], currentDepth + 1, path)); }
internal TreeIterState(TTreeNode node, TreeTraversalParameters <TTreeNode> traversalParameters, TreeNodePath nodePath = null) { m_traversalParameters = traversalParameters; this.Target = node; this.CurrentNumberOfEvaluations = 0; if (nodePath != null) { this.TargetPath = nodePath; } else { this.TargetPath = new TreeNodePath(); } }
public TreeEvalItem(TTreeNode node, TreeNodePath path) { this.Node = node; this.NodePath = path; }
internal static TreeIter <TTreeNode> CreateIteratorAtNodePath(TTreeNode root, TreeNodePath nodePath, TreeTraversalParameters <TTreeNode> traversalParameters, GetTreeNodeChildren <TTreeNode> getChildrenMethodOverride = null, GetTreeNodeParent <TTreeNode> getParentMethodOverride = null) { // If the node path is empty, then we're creating one from the root if (nodePath.Count == 0) { return(new TreeIter <TTreeNode>(root, traversalParameters)); } if (traversalParameters.FlowDirection == eTraversalFlowDirection.ThroughParents) { // Why is this not supported Debug.Fail("Node pathing through parents is not supported"); } else if (traversalParameters.FlowDirection == eTraversalFlowDirection.ThroughChildren) { // Otherwise we are creating an iterator for the node's parent, but with the next evaluations stocked starting at the final nodepath piece, // then we can just increment by one. This enables us to use the siblings to the indicated start node. TTreeNode parentNode = TreeTraversal <TTreeNode> .ParentNodeFromPath(root, nodePath); if (parentNode == null) { return(End); } var justBeforeIter = new TreeIter <TTreeNode>(parentNode, nodePath, traversalParameters, getChildrenMethodOverride, getParentMethodOverride); return(++justBeforeIter); } else if (traversalParameters.FlowDirection == eTraversalFlowDirection.ReversedThroughChildren) { Debug.Fail("Node pathing through parents is not supported"); } return(End); }
private static int CompareTreeNodePaths_ReverseBreadthFirst(TreeNodePath left, TreeNodePath right) { throw new NotImplementedException("Reverse methods not implemented yet"); }
private static int CompareTreeNodePaths_ThroughParents(TreeNodePath left, TreeNodePath right) { throw new NotSupportedException("I'm just not sure about parent traversal right now..."); }
public TTreeNode NodeAt(TreeNodePath nodePath) { return(TreeTraversal <TTreeNode> .NodeAt(this.Root, nodePath, this.GetChildrenOverride, this.GetParentOverride)); }
public TreeIter <TTreeNode> IteratorAt(TreeNodePath nodePath, Predicate <TTreeNode> predicate = null, eTraversalFlowDirection flowDirection = TreeTraversal <TTreeNode> .DefaultTraversalFlowDirection, eTraversalStrategy strategy = TreeTraversal <TTreeNode> .DefaultTraversalStrategy, bool includeRoot = true, LevelRestriction depthLimits = null) { return(TreeTraversal <TTreeNode> .IteratorAt(this.Root, nodePath, predicate, flowDirection, strategy, includeRoot, depthLimits, this.GetChildrenOverride, this.GetParentOverride)); }
internal TreeNodePath(TreeNodePath other) : this(new List <int>(other.m_actualIndexList)) { }