public TargetAnalyzer(Node myStart, Node myEnd, byte myMaxPathLength) { _Paths = new HashSet<List<long>>(); _TempList = new List<long>(); _Start = myStart; _End = myEnd; if (myMaxPathLength != 0) { _MaxPathLength = Convert.ToByte(myMaxPathLength - 1); } else { _MaxPathLength = Convert.ToByte(myMaxPathLength); } }
/// <summary> /// Please look at the class documentation for detailed description how this algorithm works. /// </summary> /// <param name="myTypeAttribute">The Attribute representing the edge to follow (p.e. "Friends")</param> /// <param name="myStart">The start node</param> /// <param name="myEnd">The end node</param> /// <param name="shortestOnly">true, if only shortest path shall be found</param> /// <param name="findAll">if true and shortestOnly is true, all shortest paths will be found. if true, and shortest only is false, all paths will be searched</param> /// <param name="myMaxDepth">The maximum depth to search</param> /// <param name="myMaxPathLength">The maximum path length which shall be analyzed</param> /// <returns>A HashSet which contains all found paths. Every path is represented by a List of ObjectUUIDs</returns>m> public HashSet<List<long>> Find(IAttributeDefinition myTypeAttribute, IVertex myStart, IVertex myEnd, bool shortestOnly, bool findAll, byte myMaxDepth, byte myMaxPathLength) { #region declarations //queue for BFS var queueLeft = new Queue<IVertex>(); var queueRight = new Queue<IVertex>(); //Dictionary to store visited TreeNodes var visitedNodesLeft = new Dictionary<long, Node>(); var visitedNodesRight = new Dictionary<long, Node>(); var visitedVerticesLeft = new HashSet<long>(); var visitedVerticesRight = new HashSet<long>(); //set current depth left byte depthLeft = 2; //set current depth right byte depthRight = 1; //maximum depth byte maxDepthLeft = 0; byte maxDepthRight = 0; #region initialize maxDepths //if the maxDepth is greater then maxPathLength, then set maxDepth to maxPathLength if (myMaxDepth > myMaxPathLength) { myMaxDepth = myMaxPathLength; } //set depth for left side maxDepthLeft = Convert.ToByte(myMaxDepth / 2 + 1); //if myMaxDepth is 1 maxDepthRight keeps 0, just one side is searching if (myMaxDepth > 1) { //both sides have the same depth maxDepthRight = maxDepthLeft; } //if myMaxDepth is even, one side has to search in a greater depth if ((myMaxDepth % 2) == 0) { maxDepthRight = Convert.ToByte(maxDepthLeft - 1); } #endregion //shortest path length byte shortestPathLength = 0; //target node, the target of the select var target = new Node(myEnd.VertexID); var root = new Node(myStart.VertexID); HashSet<long> rootFriends = new HashSet<long>(); //dummy node to check in which level the BFS is IVertex dummyLeft = null; IVertex dummyRight = null; #endregion #region BidirectionalBFS //check if the EdgeType is ASetReferenceEdgeType #region initialize variables //enqueue start node to start from left side queueLeft.Enqueue(myStart); //enqueue dummyLeft to analyze the depth of the left side queueLeft.Enqueue(dummyLeft); //enqueue target node to start from right side queueRight.Enqueue(myEnd); //enqueue dummyRight to analyze the depth of the right side queueRight.Enqueue(dummyRight); visitedNodesLeft.Add(root.Key, root); //add root and target to visitedNodes visitedNodesRight.Add(target.Key, target); #endregion #region check if start has outgoing and target has incoming edge if (!myStart.HasOutgoingEdge(myTypeAttribute.ID)) { return null; } if (!myEnd.HasIncomingVertices(myEnd.VertexTypeID, myTypeAttribute.ID)) { return null; } #endregion //if there is more than one object in the queue and the actual depth is less than MaxDepth while (((queueLeft.Count > 0) && (queueRight.Count > 0)) && ((depthLeft <= maxDepthLeft) || (depthRight <= maxDepthRight))) { #region both queues contain objects and both depths are not reached if (((queueLeft.Count > 0) && (queueRight.Count > 0)) && ((depthLeft <= maxDepthLeft) && (depthRight <= maxDepthRight))) { #region check if there is a dummyNode at the beginning of a queue //first of left queue is a dummy if (queueLeft.First<IVertex>() == null) { //if maxDepth of a side is reached and there is a dummy, one level is totaly searched if (depthLeft == maxDepthLeft) { depthLeft++; continue; } //dequeue dummy queueLeft.Dequeue(); //increase depth depthLeft++; //if left queue is empty continue if (queueLeft.Count == 0) { continue; } //enqueue dummy else { queueLeft.Enqueue(dummyLeft); } } //first of right queue is a dummy if (queueRight.First<IVertex>() == null) { //if maxDepth of a side is reached and there is a dummy, one level is totaly searched if (depthRight == maxDepthRight) { depthRight++; continue; } //dequeue dummy queueRight.Dequeue(); //increase depth depthRight++; //if right queue is empty continue if (queueRight.Count == 0) { continue; } //enqueue dummy else { queueRight.Enqueue(dummyRight); } } #endregion check if there is a dummyNode at the beginning of a queue #region get first nodes of the queues //hold the actual element of the queues Node currentNodeLeft; Node currentNodeRight; IVertex currentVertexLeft; IVertex currentVertexRight; //get the first Object of the queue currentVertexLeft = queueLeft.Dequeue(); if (visitedVerticesLeft.Contains(currentVertexLeft.VertexID)) { continue; } //get the first Object of the queue currentVertexRight = queueRight.Dequeue(); if (visitedVerticesRight.Contains(currentVertexRight.VertexID)) { //enqueue already dequeued vertex queueLeft.Enqueue(currentVertexLeft); continue; } visitedVerticesLeft.Add(currentVertexLeft.VertexID); visitedVerticesRight.Add(currentVertexRight.VertexID); if (visitedNodesLeft.ContainsKey(currentVertexLeft.VertexID)) { currentNodeLeft = visitedNodesLeft[currentVertexLeft.VertexID]; } else { currentNodeLeft = new Node(currentVertexLeft.VertexID); } if (visitedNodesRight.ContainsKey(currentVertexRight.VertexID)) { currentNodeRight = visitedNodesRight[currentVertexRight.VertexID]; } else { currentNodeRight = new Node(currentVertexRight.VertexID); } #endregion #region the edge and the backwardedge are existing if (currentVertexLeft.HasOutgoingEdge(myTypeAttribute.ID) && currentVertexRight.HasIncomingVertices(currentVertexRight.VertexTypeID, myTypeAttribute.ID)) { //get all referenced ObjectUUIDs using the given Edge var leftVertices = currentVertexLeft.GetOutgoingEdge(myTypeAttribute.ID).GetTargetVertices(); #region check left friends foreach (var nextLeftVertex in leftVertices) { Node nextLeftNode; #region if the child is the target if (nextLeftVertex.VertexID.Equals(target.Key)) { //set currentLeft as parent of target target.addParent(currentNodeLeft); #region check if already visited if (visitedNodesLeft.ContainsKey(nextLeftVertex.VertexID)) { //set currentLeft as parent visitedNodesLeft[nextLeftVertex.VertexID].addParent(currentNodeLeft); //set currentNodeLeft as child currentNodeLeft.addChild(visitedNodesLeft[nextLeftVertex.VertexID]); } else { //create a new node and set currentLeft = parent nextLeftNode = new Node(nextLeftVertex.VertexID, currentNodeLeft); //set currentNodeLeft as child of currentLeft currentNodeLeft.addChild(nextLeftNode); //never seen before //mark the node as visited visitedNodesLeft.Add(nextLeftNode.Key, nextLeftNode); //and put node into the queue queueLeft.Enqueue(nextLeftVertex); } #endregion #region check how much parents are searched if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } //if find all shortest paths else if (shortestOnly && findAll) { //set maxDepth to actual depth maxDepthLeft = depthLeft; maxDepthRight = depthRight; if ((depthLeft + depthRight) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight); } } #endregion } #endregion #region already visited else if (visitedNodesLeft.ContainsKey(nextLeftVertex.VertexID)) { //set currentLeft as parent visitedNodesLeft[nextLeftVertex.VertexID].addParent(currentNodeLeft); //set currentNodeLeft as child currentNodeLeft.addChild(visitedNodesLeft[nextLeftVertex.VertexID]); } #endregion already visited #region set as visited else { //create a new node and set currentLeft = parent nextLeftNode = new Node(nextLeftVertex.VertexID, currentNodeLeft); //set currentNodeLeft as child of currentLeft currentNodeLeft.addChild(nextLeftNode); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and put node into the queue queueLeft.Enqueue(nextLeftVertex); } #endregion set as visited } #endregion check left friends //get all referenced ObjectUUIDs using the given Edge var rightVertices = currentVertexRight.GetIncomingVertices(currentVertexRight.VertexTypeID, myTypeAttribute.ID); #region check right friends foreach (var nextRightVertex in rightVertices) { Node nextRightNode; #region if the child is the target if (root.Key.Equals(nextRightVertex.VertexID)) { #region check if already visited //mark node as visited if (visitedNodesRight.ContainsKey(nextRightVertex.VertexID)) { //set found children visitedNodesRight[nextRightVertex.VertexID].addChild(currentNodeRight); currentNodeRight.addParent(visitedNodesRight[nextRightVertex.VertexID]); } else { //create a new node and set currentRight = child nextRightNode = new Node(nextRightVertex.VertexID); nextRightNode.addChild(currentNodeRight); //set currentNodeRight as parent of current Right currentNodeRight.addParent(nextRightNode); //never seen before //mark the node as visited visitedNodesRight.Add(nextRightNode.Key, nextRightNode); //and look what comes on the next level of depth queueRight.Enqueue(nextRightVertex); } #endregion check if already visited #region check how much paths are searched if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } //if find all shortest paths else if (shortestOnly && findAll) { //set maxDepth to actual depth maxDepthLeft = depthLeft; maxDepthRight = depthRight; if ((depthLeft + depthRight) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight); } } #endregion check how much paths are searched } #endregion if the child is the target #region already visited else if (visitedNodesRight.ContainsKey(nextRightVertex.VertexID)) { //set found children visitedNodesRight[nextRightVertex.VertexID].addChild(currentNodeRight); currentNodeRight.addParent(visitedNodesRight[nextRightVertex.VertexID]); } #endregion already visited #region set as visited else { //create a new node and set currentRight = child nextRightNode = new Node(nextRightVertex.VertexID); nextRightNode.addChild(currentNodeRight); //set currentNodeRight as parent of current Right currentNodeRight.addParent(nextRightNode); //never seen before //mark the node as visited visitedNodesRight.Add(nextRightNode.Key, nextRightNode); //and look what comes on the next level of depth queueRight.Enqueue(nextRightVertex); } #endregion set as visited } #endregion check right friends #region build intersection of visitedNodesLeft and visitedNodesRight //marks if intersection nodes are existing bool foundIntersect = false; foreach (var node in visitedNodesLeft) { if (visitedNodesRight[node.Key] != null) { //set nodes children and parents node.Value.addChildren(visitedNodesRight[node.Key].Children); node.Value.addParents(visitedNodesRight[node.Key].Parents); //set nodes children and parents visitedNodesRight[node.Key].addChildren(node.Value.Children); visitedNodesRight[node.Key].addParents(node.Value.Parents); foundIntersect = true; } } #endregion build intersection of visitedNodesLeft and visitedNodesRight #region analyze intersection //if intersection nodes existing if (foundIntersect) { //only shortest path if (shortestOnly && !findAll) { //_Logger.Info("found shortest path..starting analyzer"); if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } //if find all shortest paths else if (shortestOnly && findAll) { //set maxDepth to actual depth maxDepthLeft = depthLeft; maxDepthRight = depthRight; if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else if (shortestPathLength == 0) { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } } } #endregion analyze intersection } #endregion the edge and the backwardedge are existing #region only the edge exists else if (currentVertexLeft.HasOutgoingEdge(myTypeAttribute.ID)) { //get all referenced ObjectUUIDs using the given Edge var leftVertices = currentVertexLeft.GetOutgoingEdge(myTypeAttribute.ID).GetTargetVertices(); #region check left friends foreach (var nextLeftVertex in leftVertices) { Node nextLeftNode; #region if the child is the target if (nextLeftVertex.VertexID.Equals(target.Key)) { //set currentLeft as parent of target target.addParent(currentNodeLeft); #region check if already visited if (visitedNodesLeft.ContainsKey(nextLeftVertex.VertexID)) { //set currentLeft as parent visitedNodesLeft[nextLeftVertex.VertexID].addParent(currentNodeLeft); //set currentNodeLeft as child currentNodeLeft.addChild(visitedNodesLeft[nextLeftVertex.VertexID]); } else { //create a new node and set currentLeft = parent nextLeftNode = new Node(nextLeftVertex.VertexID, currentNodeLeft); //set currentNodeLeft as child of currentLeft currentNodeLeft.addChild(nextLeftNode); //never seen before //mark the node as visited visitedNodesLeft.Add(nextLeftNode.Key, nextLeftNode); //and put node into the queue queueLeft.Enqueue(nextLeftVertex); } #endregion #region check how much parents are searched if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } //if find all shortest paths else if (shortestOnly && findAll) { //set maxDepth to actual depth maxDepthLeft = depthLeft; maxDepthRight = depthRight; if ((depthLeft + depthRight) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight); } } #endregion } #endregion #region already visited from right side else if (visitedNodesRight.ContainsKey(nextLeftVertex.VertexID)) { //get node Node temp = visitedNodesRight[nextLeftVertex.VertexID]; //add parent new temp.addParent(currentNodeLeft); //add as child currentNodeLeft.addChild(temp); visitedNodesRight.Remove(temp.Key); visitedNodesRight.Add(temp.Key, temp); if (visitedNodesLeft.Remove(temp.Key)) { visitedNodesLeft.Add(temp.Key, temp); } if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else if (shortestOnly && findAll) { maxDepthLeft = depthLeft; shortestPathLength = Convert.ToByte(maxDepthLeft + maxDepthRight); } } #endregion already visited from right side #region already visited else if (visitedNodesLeft.ContainsKey(nextLeftVertex.VertexID)) { //set currentLeft as parent visitedNodesLeft[nextLeftVertex.VertexID].addParent(currentNodeLeft); //set currentNodeLeft as child currentNodeLeft.addChild(visitedNodesLeft[nextLeftVertex.VertexID]); } #endregion already visited #region set as visited else { //create a new node and set currentLeft = parent nextLeftNode = new Node(nextLeftVertex.VertexID, currentNodeLeft); //set currentNodeLeft as child of currentLeft currentNodeLeft.addChild(nextLeftNode); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and put node into the queue queueLeft.Enqueue(nextLeftVertex); } #endregion set as visited } #endregion check left friends } #endregion only the edge exists #region only the backwardedge exists else if (currentVertexRight.HasIncomingVertices(currentVertexRight.VertexTypeID, myTypeAttribute.ID)) { //get all referenced ObjectUUIDs using the given Edge var rightVertices = currentVertexRight.GetIncomingVertices(currentVertexRight.VertexTypeID, myTypeAttribute.ID); #region check right friends foreach (var nextRightVertex in rightVertices) { Node nextRightNode; #region if the child is the target if (root.Key.Equals(nextRightVertex.VertexID)) { #region check if already visited //mark node as visited if (visitedNodesRight.ContainsKey(nextRightVertex.VertexID)) { //set found children visitedNodesRight[nextRightVertex.VertexID].addChild(currentNodeRight); currentNodeRight.addParent(visitedNodesRight[nextRightVertex.VertexID]); } else { //create a new node and set currentRight = child nextRightNode = new Node(nextRightVertex.VertexID); nextRightNode.addChild(currentNodeRight); //set currentNodeRight as parent of current Right currentNodeRight.addParent(nextRightNode); //never seen before //mark the node as visited visitedNodesRight.Add(nextRightNode.Key, nextRightNode); //and look what comes on the next level of depth queueRight.Enqueue(nextRightVertex); } #endregion check if already visited #region check how much paths are searched if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } //if find all shortest paths else if (shortestOnly && findAll) { //set maxDepth to actual depth maxDepthLeft = depthLeft; maxDepthRight = depthRight; if ((depthLeft + depthRight) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight); } } #endregion check how much paths are searched } #endregion if the child is the target #region already visited from left side else if (visitedNodesLeft.ContainsKey(nextRightVertex.VertexID)) { //get node Node temp = visitedNodesLeft[nextRightVertex.VertexID]; temp.addChild(currentNodeRight); currentNodeRight.addParent(temp); visitedNodesLeft.Remove(temp.Key); visitedNodesLeft.Add(temp.Key, temp); if (visitedNodesRight.Remove(temp.Key)) { visitedNodesRight.Add(temp.Key, temp); } if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else if (shortestOnly && findAll) { maxDepthRight = depthRight; shortestPathLength = Convert.ToByte(maxDepthLeft + maxDepthRight); } } #endregion already visited from left side #region already visited else if (visitedNodesRight.ContainsKey(nextRightVertex.VertexID)) { //set found children visitedNodesRight[nextRightVertex.VertexID].addChild(currentNodeRight); currentNodeRight.addParent(visitedNodesRight[nextRightVertex.VertexID]); } #endregion already visited #region set as visited else { //create a new node and set currentRight = child nextRightNode = new Node(nextRightVertex.VertexID); nextRightNode.addChild(currentNodeRight); //set currentNodeRight as parent of current Right currentNodeRight.addParent(nextRightNode); //never seen before //mark the node as visited visitedNodesRight.Add(nextRightNode.Key, nextRightNode); //and look what comes on the next level of depth queueRight.Enqueue(nextRightVertex); } #endregion set as visited } #endregion check right friends } #endregion only the backwardedge exists } #endregion both queues contain objects and both depths are not reached #region only left queue contain objects else if ((queueLeft.Count > 0) && (depthLeft <= maxDepthLeft)) { #region check if first element of queue is a dummy //dummy if (queueLeft.First<IVertex>() == null) { queueLeft.Dequeue(); depthLeft++; if (queueLeft.Count == 0) { continue; } else if (depthLeft > maxDepthLeft) { continue; } } #endregion check if first element of queue is a dummy #region get first nodes of the queues //hold the actual element of the queues Node currentNodeLeft; IVertex currentVertexLeft; //get the first Object of the queue currentVertexLeft = queueLeft.Dequeue(); if (visitedVerticesLeft.Contains(currentVertexLeft.VertexID)) { continue; } visitedVerticesLeft.Add(currentVertexLeft.VertexID); if (visitedNodesLeft.ContainsKey(currentVertexLeft.VertexID)) { currentNodeLeft = visitedNodesLeft[currentVertexLeft.VertexID]; } else { currentNodeLeft = new Node(currentVertexLeft.VertexID); } #endregion if (currentVertexLeft.HasOutgoingEdge(myTypeAttribute.ID)) { //get all referenced ObjectUUIDs using the given Edge var leftVertices = currentVertexLeft.GetOutgoingEdge(myTypeAttribute.ID).GetTargetVertices(); #region check left friends foreach (var nextLeftVertex in leftVertices) { Node nextLeftNode; #region if the child is the target if (nextLeftVertex.VertexID.Equals(target.Key)) { //set currentLeft as parent of target target.addParent(currentNodeLeft); #region check if already visited if (visitedNodesLeft.ContainsKey(nextLeftVertex.VertexID)) { //set currentLeft as parent visitedNodesLeft[nextLeftVertex.VertexID].addParent(currentNodeLeft); //set currentNodeLeft as child currentNodeLeft.addChild(visitedNodesLeft[nextLeftVertex.VertexID]); } else { //create a new node and set currentLeft = parent nextLeftNode = new Node(nextLeftVertex.VertexID, currentNodeLeft); //set currentNodeLeft as child of currentLeft currentNodeLeft.addChild(nextLeftNode); //never seen before //mark the node as visited visitedNodesLeft.Add(nextLeftNode.Key, nextLeftNode); //and put node into the queue queueLeft.Enqueue(nextLeftVertex); } #endregion #region check how much parents are searched if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } //if find all shortest paths else if (shortestOnly && findAll) { //set maxDepth to actual depth maxDepthLeft = depthLeft; maxDepthRight = depthRight; if ((depthLeft + depthRight) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight); } } #endregion } #endregion #region already visited from right side else if (visitedNodesRight.ContainsKey(nextLeftVertex.VertexID)) { //get node Node temp = visitedNodesRight[nextLeftVertex.VertexID]; //add parent new temp.addParent(currentNodeLeft); //add as child currentNodeLeft.addChild(temp); visitedNodesRight.Remove(temp.Key); visitedNodesRight.Add(temp.Key, temp); if (visitedNodesLeft.Remove(temp.Key)) { visitedNodesLeft.Add(temp.Key, temp); } if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else if (shortestOnly && findAll) { maxDepthLeft = depthLeft; shortestPathLength = Convert.ToByte(maxDepthLeft + maxDepthRight); } } #endregion already visited from right side #region already visited else if (visitedNodesLeft.ContainsKey(nextLeftVertex.VertexID)) { //set currentLeft as parent visitedNodesLeft[nextLeftVertex.VertexID].addParent(currentNodeLeft); //set currentNodeLeft as child currentNodeLeft.addChild(visitedNodesLeft[nextLeftVertex.VertexID]); } #endregion already visited #region set as visited else { //create a new node and set currentLeft = parent nextLeftNode = new Node(nextLeftVertex.VertexID, currentNodeLeft); //set currentNodeLeft as child of currentLeft currentNodeLeft.addChild(nextLeftNode); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and put node into the queue queueLeft.Enqueue(nextLeftVertex); } #endregion set as visited } #endregion check left friends } } #endregion only left queue contain objects #region only right queue contain objects else if ((queueRight.Count > 0) && (depthRight <= maxDepthRight)) { #region check if first element of the queue is a dummy //dummy if (queueRight.First<IVertex>() == null) { queueRight.Dequeue(); depthRight++; if (queueRight.Count == 0) { continue; } } #endregion check if first element of the queue is a dummy #region get first nodes of the queues //hold the actual element of the queues Node currentNodeRight; IVertex currentVertexRight; //get the first Object of the queue currentVertexRight = queueRight.Dequeue(); if (visitedVerticesRight.Contains(currentVertexRight.VertexID)) { continue; } visitedVerticesRight.Add(currentVertexRight.VertexID); if (visitedNodesRight.ContainsKey(currentVertexRight.VertexID)) { currentNodeRight = visitedNodesRight[currentVertexRight.VertexID]; } else { currentNodeRight = new Node(currentVertexRight.VertexID); } #endregion if (currentVertexRight.HasIncomingVertices(currentVertexRight.VertexTypeID, myTypeAttribute.ID)) { //get all referenced ObjectUUIDs using the given Edge var rightVertices = currentVertexRight.GetIncomingVertices(currentVertexRight.VertexTypeID, myTypeAttribute.ID); #region check right friends foreach (var nextRightVertex in rightVertices) { Node nextRightNode; #region if the child is the target if (root.Key.Equals(nextRightVertex.VertexID)) { #region check if already visited //mark node as visited if (visitedNodesRight.ContainsKey(nextRightVertex.VertexID)) { //set found children visitedNodesRight[nextRightVertex.VertexID].addChild(currentNodeRight); currentNodeRight.addParent(visitedNodesRight[nextRightVertex.VertexID]); } else { //create a new node and set currentRight = child nextRightNode = new Node(nextRightVertex.VertexID); nextRightNode.addChild(currentNodeRight); //set currentNodeRight as parent of current Right currentNodeRight.addParent(nextRightNode); //never seen before //mark the node as visited visitedNodesRight.Add(nextRightNode.Key, nextRightNode); //and look what comes on the next level of depth queueRight.Enqueue(nextRightVertex); } #endregion check if already visited #region check how much paths are searched if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } //if find all shortest paths else if (shortestOnly && findAll) { //set maxDepth to actual depth maxDepthLeft = depthLeft; maxDepthRight = depthRight; if ((depthLeft + depthRight) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight); } } #endregion check how much paths are searched } #endregion if the child is the target #region already visited from left side else if (visitedNodesLeft.ContainsKey(nextRightVertex.VertexID)) { //get node Node temp = visitedNodesLeft[nextRightVertex.VertexID]; temp.addChild(currentNodeRight); currentNodeRight.addParent(temp); visitedNodesLeft.Remove(temp.Key); visitedNodesLeft.Add(temp.Key, temp); if (visitedNodesRight.Remove(temp.Key)) { visitedNodesRight.Add(temp.Key, temp); } if (shortestOnly && !findAll) { if ((depthLeft + depthRight + 1) > myMaxPathLength) { shortestPathLength = myMaxPathLength; } else { shortestPathLength = Convert.ToByte(depthLeft + depthRight + 1); } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else if (shortestOnly && findAll) { maxDepthRight = depthRight; shortestPathLength = Convert.ToByte(maxDepthLeft + maxDepthRight); } } #endregion already visited from left side #region already visited else if (visitedNodesRight.ContainsKey(nextRightVertex.VertexID)) { //set found children visitedNodesRight[nextRightVertex.VertexID].addChild(currentNodeRight); currentNodeRight.addParent(visitedNodesRight[nextRightVertex.VertexID]); } #endregion already visited #region set as visited else { //create a new node and set currentRight = child nextRightNode = new Node(nextRightVertex.VertexID); nextRightNode.addChild(currentNodeRight); //set currentNodeRight as parent of current Right currentNodeRight.addParent(nextRightNode); //never seen before //mark the node as visited visitedNodesRight.Add(nextRightNode.Key, nextRightNode); //and look what comes on the next level of depth queueRight.Enqueue(nextRightVertex); } #endregion set as visited } #endregion check right friends } } #endregion only right queue contain objects #region abort loop else { break; } #endregion abort loop } //get result paths #region start TargetAnalyzer if (shortestOnly && findAll) { if (shortestPathLength > myMaxPathLength) { shortestPathLength = myMaxPathLength; } return new TargetAnalyzer(root, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else { return new TargetAnalyzer(root, target, myMaxPathLength, shortestOnly, findAll).getPaths(); } #endregion start TargetAnalyzer #endregion BidirectionalBFS }
public Node(long myObjectID, Node myParent) : this(myObjectID) { _Parents.Add(myParent); }
/// <summary> /// Fügt dem Knoten ein Parent hinzu, existiert dieser schon, werden die Parents und Children des existierenden aktualisiert. /// </summary> /// <param name="myParent">Parent welcher hinzugefügt werden soll.</param> /// <returns></returns> public bool addParent(Node myParent) { bool equal = false; foreach (var thisParent in _Parents) { //check if the node wich should be added IS already existing if (thisParent.Equals(myParent)) { //exists equal = true; break; } } //node is NOT already existing, add if (!equal) { return _Parents.Add(myParent); } return false; }
/// <summary> /// Fügt dem Knoten ein Child hinzu, existiert dieser schon, werden die Parents und Children des existierenden aktualisiert. /// </summary> /// <param name="myChild">Child welches hinzugefügt werden soll.</param> /// <returns></returns> public bool addChild(Node myChild) { bool equal = false; foreach (var thisChild in _Children) { //check if the node wich should be added IS already existing if (thisChild.Equals(myChild)) { equal = true; break; } } if (!equal) { return _Children.Add(myChild); } return false; }
public TargetAnalyzer(Node myStart, Node myEnd, byte myMaxPathLength, bool myShortestOnly, bool myFindAll) : this(myStart, myEnd, myMaxPathLength) { _ShortestOnly = myShortestOnly; _FindAll = myFindAll; }
private void getPath(Node myCurrent) { if (!_TempList.Contains(myCurrent.Key)) { //add myCurrent to actual path _TempList.Add(myCurrent.Key); //set flag to mark that myCurrent is in actual path myCurrent.AlreadyInPath = true; //abort recursion when myCurrent is the root node if (_Start.Key.Equals(myCurrent.Key)) { //duplicate list var temp = new List<long>(_TempList); //reverse because the path is calculated beginning at the target temp.Reverse(); //add completed path to result list _Paths.Add(temp); } foreach (Node parent in myCurrent.Parents) { //if parent node not already in actual path if (!parent.AlreadyInPath) { //and MaxPathLength is not reached if (_TempList.Count < _MaxPathLength) { getPath(parent); } } } if (_TempList.Count != 0) { //remove last node from actual path _TempList.Remove(_TempList.Last<long>()); //myCurrent isn't in actual path myCurrent.AlreadyInPath = false; } } return; }
///// <summary> ///// Sucht im Graphen nach Knoten "myEnd" ausgehend vom Knoten "myStart", bis zur max. Tiefe "myMaxDepth". ///// </summary> ///// <param name="myTypeAttribute">Kante über die gesucht werden soll</param> ///// <param name="myDBContext"></param> ///// <param name="myStart">Startknoten</param> ///// <param name="myEnd">gesuchter Knoten</param> ///// <param name="myMaxDepth">max. Tiefe</param> ///// <returns>true wenn gesuchter Knoten min. 1 mal gefunden, false sonst</returns> //public bool Find(IAttributeDefinition myTypeAttribute, IVertex myStart, IVertex myEnd, byte myMaxDepth) //{ // #region data // //queue for BFS // Queue<long> queue = new Queue<ObjectUUID>(); // //Dictionary to store visited TreeNodes // HashSet<ObjectUUID> visitedNodes = new HashSet<ObjectUUID>(); // //current depth // byte depth = 1; // //first node in path tree, the start of the select // ObjectUUID root = myStart.ObjectUUID; // //target node, the target of the select // ObjectUUID target = myEnd.ObjectUUID; // //dummy node to check in which level the BFS is // ObjectUUID dummy = null; // //enqueue first node to start the BFS // queue.Enqueue(root); // queue.Enqueue(dummy); // //add root to visitedNodes // visitedNodes.Add(root); // //holds the actual DBObject // Exceptional<DBObjectStream> currentDBObject; // #endregion data // #region BFS // #region validate root // //check if root has edge // var dbo = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), root); // if (dbo.Failed()) // { // throw new NotImplementedException(); // } // if (!dbo.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) // { // return false; // } // #endregion validate root // //if there is more than one object in the queue and the actual depth is less than MaxDepth // while ((queue.Count > 1) && (depth <= myMaxDepth)) // { // //get the first Object of the queue // ObjectUUID nodeOfQueue = queue.Dequeue(); // #region check if nodeOfQueue is a dummy // //if nodeOfQueue is a dummy, this level is completely worked off // if (nodeOfQueue == null) // { // depth++; // queue.Enqueue(nodeOfQueue); // continue; // } // #endregion check if current is a dummy // //load DBObject // currentDBObject = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), nodeOfQueue); // if (currentDBObject.Failed()) // { // throw new NotImplementedException(); // } // if (currentDBObject.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) // { // #region EdgeType is ASetOfReferencesEdgeType // if (myTypeAttribute.EdgeType is ASetOfReferencesEdgeType) // { // //get all referenced ObjectUUIDs using the given Edge // var objectUUIDs = (currentDBObject.Value.GetAttribute(myTypeAttribute.UUID) as ASetOfReferencesEdgeType).GetAllReferenceIDs(); // ObjectUUID currentNode; // foreach (ObjectUUID obj in objectUUIDs) // { // #region obj is target // //if the child is the target // if (target.Equals(obj)) // { // return true; // } // #endregion obj is target // #region never seen before // else if (!visitedNodes.Contains(obj)) // { // //create new node and set nodeOfQueue as parent // currentNode = new ObjectUUID(obj.ToString()); // //mark the node as visited // visitedNodes.Add(currentNode); // //put created node in queue // queue.Enqueue(currentNode); // } // #endregion never seen before // } // } // #endregion EdgeType is ASetOfReferencesEdgeType // #region EdgeType is ASingleReferenceEdgeType // else if (myTypeAttribute.EdgeType is ASingleReferenceEdgeType) // { // //get all referenced ObjectUUIDs using the given Edge // var objectUUIDs = (currentDBObject.Value.GetAttribute(myTypeAttribute.UUID) as ASingleReferenceEdgeType).GetAllReferenceIDs(); // ObjectUUID objectUUID = objectUUIDs.First<ObjectUUID>(); // ObjectUUID currentNode; // #region obj is target // //if the child is the target // if (target.Equals(objectUUID)) // { // return true; // } // #endregion obj is target // #region never seen before // else if (!visitedNodes.Contains(objectUUID)) // { // //create new node and set nodeOfQueue as parent // currentNode = new ObjectUUID(objectUUID.ToString()); // //mark the node as visited // visitedNodes.Add(currentNode); // //put created node in queue // queue.Enqueue(currentNode); // } // #endregion never seen before // } // #endregion EdgeType is ASingleReferenceEdgeType // else // { // throw new NotImplementedException(); // } // } // } // #endregion BFS // return false; //} ///// <summary> ///// Sucht im Graphen nach Knoten "myEnd" ausgehend von der Knotenmenge "myEdge", bis zur max. Tiefe "myMaxDepth". ///// </summary> ///// <param name="myTypeAttribute">Kante über die gesucht werden soll</param> ///// <param name="myDBContext"></param> ///// <param name="myStart">Startknoten</param> ///// <param name="myEnd">gesuchter Knoten</param> ///// <param name="myEdge">Menge an Knoten, ausgehend vom Startknoten welche mittels einer Funktion eingeschränkt wurde</param> ///// <param name="myMaxDepth">max. Tiefe</param> ///// <returns>true wenn gesuchter Knoten min. 1 mal gefunden, false sonst</returns> //public bool Find(IAttributeDefinition myTypeAttribute, IVertex myStart, IVertex myEnd, IEdge myEdge, byte myMaxDepth) //{ // #region data // //queue for BFS // Queue<ObjectUUID> queue = new Queue<ObjectUUID>(); // //Dictionary to store visited TreeNodes // BigHashSet<ObjectUUID> visitedNodes = new BigHashSet<ObjectUUID>(); // //current depth // byte depth = 2; // //first node in path tree, the start of the select // ObjectUUID root = myStart.ObjectUUID; // //constrainted set of nodes, of start node // HashSet<ObjectUUID> rootFriends = new HashSet<ObjectUUID>(); // //target node, the target of the select // ObjectUUID target = myEnd.ObjectUUID; // //dummy node to check in which level the BFS is // ObjectUUID dummy = null; // //add root to visitedNodes // visitedNodes.Add(root); // //holds the actual DBObject // Exceptional<DBObjectStream> currentDBObject; // #endregion data // #region validate root // //check if root has edge // var dbo = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), root); // if (dbo.Failed()) // { // throw new NotImplementedException(); // } // if (!dbo.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) // { // return false; // } // #endregion validate root // #region get friends of startElement and check if they are the target and valid // //instead of inserting only the startObject, we are using the startObject and the friends of the startObject (which could be restricted) // var firstUUIDs = myEdge.GetAllReferenceIDs(); // for (int i = 0; i < firstUUIDs.Count(); i++) // { // var element = firstUUIDs.ElementAt(i); // if (element != null) // { // //create a new node and set root = parent // var currentNode = element; // #region check if the child is the target // //start and target are conntected directly // if (currentNode.Equals(myEnd.ObjectUUID)) // { // //add node (which coud be the target) to startFriends (if start and target are directly connected, the target in the rootFriends list is needed) // rootFriends.Add(currentNode); // return true; // } // #endregion check if the child is the target // //check if element has edge // var dbobject = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), currentNode); // if (dbobject.Failed()) // { // continue; // } // if (!dbobject.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) // { // continue; // } // //enqueue node to start from left side // queue.Enqueue(currentNode); // //add node to visitedNodes // visitedNodes.Add(currentNode); // //add node to startFriends // rootFriends.Add(currentNode); // } // } // #endregion get friends of startElement and check if they are the target and valid // //enqueue dummy // queue.Enqueue(dummy); // #region BFS // //if there is more than one object in the queue and the actual depth is less than MaxDepth // while ((queue.Count > 1) && (depth <= myMaxDepth)) // { // //get the first Object of the queue // ObjectUUID nodeOfQueue = queue.Dequeue(); // #region check if nodeOfQueue is a dummy // //if nodeOfQueue is a dummy, this level is completely worked off // if (nodeOfQueue == null) // { // depth++; // queue.Enqueue(nodeOfQueue); // continue; // } // #endregion check if current is a dummy // //load DBObject // currentDBObject = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), nodeOfQueue); // if (currentDBObject.Failed()) // { // throw new NotImplementedException(); // } // if (currentDBObject.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) // { // #region EdgeType is ASetOfReferencesEdgeType // if (myTypeAttribute.EdgeType is ASetOfReferencesEdgeType) // { // //get all referenced ObjectUUIDs using the given Edge // var objectUUIDs = (currentDBObject.Value.GetAttribute(myTypeAttribute.UUID) as ASetOfReferencesEdgeType).GetAllReferenceIDs(); // ObjectUUID currentNode; // foreach (ObjectUUID obj in objectUUIDs) // { // #region obj is target // //if the child is the target // if (target.Equals(obj)) // { // return true; // } // #endregion obj is target // #region never seen before // else if (!visitedNodes.Contains(obj)) // { // //create new node and set nodeOfQueue as parent // currentNode = new ObjectUUID(obj.ToString()); // //mark the node as visited // visitedNodes.Add(currentNode); // //put created node in queue // queue.Enqueue(currentNode); // } // #endregion never seen before // } // } // #endregion EdgeType is ASetOfReferencesEdgeType // #region EdgeType is ASingleReferenceEdgeType // else if (myTypeAttribute.EdgeType is ASingleReferenceEdgeType) // { // //get all referenced ObjectUUIDs using the given Edge // var objectUUIDs = (currentDBObject.Value.GetAttribute(myTypeAttribute.UUID) as ASingleReferenceEdgeType).GetAllReferenceIDs(); // ObjectUUID objectUUID = objectUUIDs.First<ObjectUUID>(); // ObjectUUID currentNode; // #region obj is target // //if the child is the target // if (target.Equals(objectUUID)) // { // return true; // } // #endregion obj is target // #region never seen before // else if (!visitedNodes.Contains(objectUUID)) // { // //create new node and set nodeOfQueue as parent // currentNode = new ObjectUUID(objectUUID.ToString()); // //mark the node as visited // visitedNodes.Add(currentNode); // //put created node in queue // queue.Enqueue(currentNode); // } // #endregion never seen before // } // #endregion EdgeType is ASingleReferenceEdgeType // else // { // throw new NotImplementedException(); // } // } // } // #endregion BFS // return false; //} /// <summary> /// Searches shortest, all shortest or all paths starting from "myStart" to "myEnd". /// </summary> /// <param name="myTypeAttribute">The Attribute representing the edge to follow (p.e. "Friends")</param> /// <param name="myTypeManager">The TypeManager for the Node type</param> /// <param name="myDBObjectCache">The Object Cache for faster object lookup</param> /// <param name="myStart">The start node</param> /// <param name="myEnd">The end node</param> /// <param name="shortestOnly">true, if only shortest path shall be found</param> /// <param name="findAll">if true and shortestOnly is true, all shortest paths will be found. if true, and shortest only is false, all paths will be searched</param> /// <param name="myMaxDepth">The maximum depth to search</param> /// <param name="myMaxPathLength">The maximum path length which shall be analyzed</param> /// <returns>A HashSet which contains all found paths. Every path is represented by a List of ObjectUUIDs</returns> public HashSet<List<long>> Find(IAttributeDefinition myTypeAttribute, IVertex myStart, IVertex myEnd, bool shortestOnly, bool findAll, byte myMaxDepth, byte myMaxPathLength) { #region data //queue for BFS Queue<IVertex> queue = new Queue<IVertex>(); //Dictionary to store visited TreeNodes Dictionary<long, Node> visitedNodes = new Dictionary<long, Node>(); HashSet<long> visitedVertices = new HashSet<long>(); //current depth byte depth = 0; //first node in path tree, the start of the select Node root = new Node(myStart.VertexID); //target node, the target of the select Node target = new Node(myEnd.VertexID); //dummy node to check in which level the BFS is IVertex dummy = null; //if the maxDepth is greater then maxPathLength, then set maxDepth to maxPathLength if (myMaxDepth > myMaxPathLength) { myMaxDepth = myMaxPathLength; } //enqueue first node to start the BFS queue.Enqueue(myStart); queue.Enqueue(dummy); //add root to visitedNodes visitedNodes.Add(root.Key, root); #endregion #region BFS //check if root node has edge and target has backwardedge if (!myStart.HasOutgoingEdge(myTypeAttribute.ID)) { return null; } if (!myEnd.HasIncomingVertices(myEnd.VertexTypeID, myTypeAttribute.ID)) { return null; } //if there is more than one object in the queue and the actual depth is less than MaxDepth while ((queue.Count > 0) && (depth <= myMaxDepth)) { //get the first Object of the queue IVertex currentVertex = queue.Dequeue(); //dummy if (currentVertex == null || visitedVertices.Contains(currentVertex.VertexID)) { continue; } visitedVertices.Add(currentVertex.VertexID); Node currentNode; if (visitedNodes.ContainsKey(currentVertex.VertexID)) { currentNode = visitedNodes[currentVertex.VertexID]; } else { currentNode = new Node(currentVertex.VertexID); } if (currentVertex.HasOutgoingEdge(myTypeAttribute.ID)) { var vertices = currentVertex.GetOutgoingEdge(myTypeAttribute.ID).GetTargetVertices(); Node nextNode; foreach (var vertex in vertices) { //create a new node and set currentNode = parent, nextNode = child nextNode = new Node(vertex.VertexID, currentNode); currentNode.addChild(nextNode); //if the child is the target if (nextNode.Equals(target)) { //node points on the target target.Parents.Add(currentNode); //if shortestOnly == true we are finished here if (shortestOnly) { if (findAll) { //continue searching the current depth if there are any other shortest paths myMaxDepth = Convert.ToByte(depth); myMaxPathLength = Convert.ToByte(depth + 2); } else { //got the shortest, finished return new TargetAnalyzer(root, target, myMaxPathLength, shortestOnly, findAll).getPaths(); } } } else { //been there before if (visitedNodes.ContainsKey(nextNode.Key)) { //node has more then one parent visitedNodes[nextNode.Key].Parents.Add(currentNode); } //never seen before //mark the node as visited visitedNodes.Add(nextNode.Key, nextNode); //and look what comes on the next level of depth queue.Enqueue(vertex); } } } //if a new depth is reached if (queue.First() == null) { //enqueue the dummy at the end of to mark the next depth queue.Enqueue(queue.Dequeue()); //one step deeper in the dungen depth++; } } #endregion //analyze paths return new TargetAnalyzer(root, target, myMaxPathLength, shortestOnly, findAll).getPaths(); }