public TargetAnalyzer(Node myStart, HashSet<ObjectUUID> myStartFriends, Node myEnd, byte myMaxPathLength) { _Paths = new HashSet<List<ObjectUUID>>(); _TempList = new List<ObjectUUID>(); _Start = myStart; _StartFriends = myStartFriends; _End = myEnd; if (myMaxPathLength != 0) { _MaxPathLength = Convert.ToByte(myMaxPathLength - 1); } else { _MaxPathLength = Convert.ToByte(myMaxPathLength); } }
public Node(ObjectUUID myObjectUUID, Node myParent) : this(myObjectUUID) { _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._Key.Equals(myParent.Key)) { //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._Key.Equals(myChild.Key)) { equal = true; break; } } if (!equal) { return _Children.Add(myChild); } 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<ObjectUUID>> Find(TypeAttribute myTypeAttribute, DBTypeManager myTypeManager, DBObjectCache myDBObjectCache, DBObjectStream myStart, DBObjectStream myEnd, bool shortestOnly, bool findAll, byte myMaxDepth, byte myMaxPathLength) { #region data //queue for BFS Queue<Node> queue = new Queue<Node>(); //Dictionary to store visited TreeNodes BigDictionary<ObjectUUID, Node> visitedNodes = new BigDictionary<ObjectUUID, Node>(); //current depth byte depth = 0; //first node in path tree, the start of the select Node root = new Node(myStart.ObjectUUID); //root changed in Dictionary because of BidirectionalBFS HashSet<ObjectUUID> rootFriends = new HashSet<ObjectUUID>(); //target node, the target of the select Node target = new Node(myEnd.ObjectUUID); //holds the key of the backwardedge EdgeKey edgeKey = new EdgeKey(myTypeAttribute); //dummy node to check in which level the BFS is Node dummy = new Node(); //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(root); queue.Enqueue(dummy); //add root to visitedNodes visitedNodes.Add(root.Key, root); //holds the actual DBObject Exceptional<DBObjectStream> currentDBObject; #endregion #region BFS //Log start ////_Logger.Info("Starting BFS.."); //check if root node has edge and target has backwardedge var dbObject = myDBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myTypeManager), root.Key); if (dbObject.Failed()) { throw new NotImplementedException(); } if (!dbObject.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myTypeManager))) { ////_Logger.Info("Abort search! Start object has no edge!"); //Console.WriteLine("No paths found!"); return null; } var be = myDBObjectCache.LoadDBBackwardEdgeStream(myTypeAttribute.GetRelatedType(myTypeManager), target.Key); if (be.Failed()) { throw new NotImplementedException(); } if (!be.Value.ContainsBackwardEdge(edgeKey)) { ////_Logger.Info("Abort search! End object has no backwardedge!"); //Console.WriteLine("No paths found!"); 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 Node current = queue.Dequeue(); //dummy if (current.Key == null) { break; } //load DBObject currentDBObject = myDBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myTypeManager), current.Key); if (currentDBObject.Failed()) { throw new NotImplementedException(); } if (currentDBObject.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myTypeManager))) { if (myTypeAttribute.EdgeType is ASetOfReferencesEdgeType) { //get all referenced ObjectUUIDs using the given Edge var objectUUIDs = (currentDBObject.Value.GetAttribute(myTypeAttribute.UUID) as ASetOfReferencesEdgeType).GetAllReferenceIDs(); Node currentNode; foreach(ObjectUUID dbo in objectUUIDs) { //only for debug //var currentNodeObject = myTypeManager.LoadDBObject(myTypeAttribute.RelatedGraphType, dbo); //create a new node and set current = parent, currentNode = child currentNode = new Node(dbo, current); //if the child is the target if (currentNode.Key.Equals(myEnd.ObjectUUID)) { //node points on the target target.Parents.Add(current); //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 { ////_Logger.Info("found shortest path."); //got the shortest, finished return new TargetAnalyzer(root, rootFriends, target, myMaxPathLength, shortestOnly, findAll).getPaths(); } } } else { //been there before if (visitedNodes.ContainsKey(currentNode.Key)) { //if currentNode.Key isn't root set parent if (!rootFriends.Contains(currentNode.Key)) { //node has more then one parent visitedNodes[currentNode.Key].Parents.Add(current); } continue; } //never seen before //mark the node as visited visitedNodes.Add(currentNode.Key, currentNode); //and look what comes on the next level of depth queue.Enqueue(currentNode); //some logging if (queue.Count % 10000 == 0) { ////_Logger.Info(queue.Count + " elements enqueued.."); } } } } else if (myTypeAttribute.EdgeType is ASingleReferenceEdgeType) { throw new NotImplementedException(); } else { throw new NotImplementedException(); } } //if a new depth is reached if (queue.First() == dummy) { //enqueue the dummy at the end of to mark the next depth queue.Enqueue(queue.Dequeue()); //one step deeper in the dungen depth++; ////_Logger.Info("going deeper in the dungeon.. current level: " + depth); } } #endregion ////_Logger.Info("finished building path-graph.. starting analyzer"); //analyze paths return new TargetAnalyzer(root, rootFriends, target, myMaxPathLength, shortestOnly, findAll).getPaths(); }
public BidirectionalTargetAnalyzer(Node myStart, Node myEnd) { _TempListLeft = new LinkedList<ObjectUUID>(); _TempListRight = new LinkedList<ObjectUUID>(); _LeftPaths = new HashSet<LinkedList<ObjectUUID>>(); _RightPaths = new HashSet<LinkedList<ObjectUUID>>(); _Paths = new HashSet<List<ObjectUUID>>(); _PathsQueue = new Queue<List<ObjectUUID>>(); _Start = myStart; _End = myEnd; }
private void getPath(Node myCurrent) { //add myCurrent to actual path _TempListLeft.AddLast(myCurrent.Key); //set flag to mark that myCurrent is in actual path myCurrent.AlreadyInPath = true; //abort recursion when myCurrent is the root node if (myCurrent.Key.Equals(_Start.Key)) { //duplicate list var temp = new List<ObjectUUID>(_TempListLeft); if (!QueueContainsList(_PathsQueue, temp)) { //turn around the path (we're currently at the root) temp.Reverse(); //add completed path to result list _PathsQueue.Enqueue(temp); //do some logging PathViewer.LogPath(temp); if (_ShortestOnly && !_FindAll) { //first path is analyzed _Done = true; //we can stop evaluating next parents return; } } } foreach (Node parent in myCurrent.Parents) { //if parent node not already in actual path if (!parent.AlreadyInPath) { //and MaxPathLength is not reached if (_TempListLeft.Count < _MaxPathLength) { if (!_Done) { getPath(parent); } } } } //remove last node from actual path _TempListLeft.RemoveLast(); //myCurrent isn't in actual path myCurrent.AlreadyInPath = false; return; }
public BidirectionalTargetAnalyzer(Node myStart, Node myEnd, byte myMaxPathLength, bool myShortestOnly, bool myFindAll) : this(myStart, myEnd) { _ShortestOnly = myShortestOnly; _FindAll = myFindAll; _MaxPathLength = myMaxPathLength; }
//Logger //private static Logger //_Logger = LogManager.GetCurrentClassLogger(); /// <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="myDBContext">The DBContext holds the TypeManager and the ObjectCache</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<ObjectUUID>> Find(TypeAttribute myTypeAttribute, DBContext myDBContext, DBObjectStream myStart, IReferenceEdge myEdge, DBObjectStream myEnd, bool shortestOnly, bool findAll, byte myMaxDepth, byte myMaxPathLength) { #region declarations //queue for BFS var queueLeft = new Queue<Node>(); var queueRight = new Queue<Node>(); //Dictionary to store visited TreeNodes var visitedNodesLeft = new BigDictionary<ObjectUUID, Node>(); var visitedNodesRight = new BigDictionary<ObjectUUID, Node>(); //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.ObjectUUID); var root = new Node(myStart.ObjectUUID); HashSet<ObjectUUID> rootFriends = new HashSet<ObjectUUID>(); //dummy node to check in which level the BFS is var dummyLeft = new Node(); var dummyRight = new Node(); #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(); foreach (var element in firstUUIDs) { if (element != null) { //create a new node and set root = parent var currentNodeLeft = new Node(element); #region check if the child is the target //start and target are conntected directly if (currentNodeLeft.Key == myEnd.ObjectUUID) { //set depthRight to zero depthRight = 0; //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(currentNodeLeft.Key); shortestPathLength = Convert.ToByte(depthLeft); return new TargetAnalyzer(root, rootFriends, target, shortestPathLength, shortestOnly, findAll).getPaths(); } #endregion check if the child is the target //check if element has edge var dbo = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), currentNodeLeft.Key); if (dbo.Failed()) { continue; } if (!dbo.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) { continue; } //enqueue node to start from left side queueLeft.Enqueue(currentNodeLeft); //add node to visitedNodes visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //add node to startFriends rootFriends.Add(currentNodeLeft.Key); } } #endregion get friends of startElement and check if they are the target and valid //elements of myEdge doesn't have edge if (visitedNodesLeft.Count == 0) { return null; } //check if target already found if (shortestPathLength != 0) { return new TargetAnalyzer(root, rootFriends, target, shortestPathLength, shortestOnly, findAll).getPaths(); } //enqueue dummyLeft to analyze the depth of the left side queueLeft.Enqueue(dummyLeft); //holds the key of the backwardedge var edgeKey = new EdgeKey(myTypeAttribute); //holds the actual DBObject Exceptional<DBObjectStream> currentDBObjectLeft; Exceptional<BackwardEdgeStream> currentDBObjectRight; #endregion declarations #region BidirectionalBFS //check if the EdgeType is ASetReferenceEdgeType #region EdgeType is ASetReferenceEdgeType if (myEdge is ASetOfReferencesEdgeType) { #region initialize variables //enqueue target node to start from right side queueRight.Enqueue(target); //enqueue dummyRight to analyze the depth of the right side queueRight.Enqueue(dummyRight); //add root and target to visitedNodes visitedNodesRight.Add(target.Key, target); #endregion initialize variables #region check if target has backwardedge var be = myDBContext.DBObjectCache.LoadDBBackwardEdgeStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), target.Key); if (be.Failed()) { throw new NotImplementedException(); } if (!be.Value.ContainsBackwardEdge(edgeKey)) { return null; } #endregion check if target has backwardedge //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))) { //hold the actual element of the queues Node currentLeft; Node currentRight; #region check if there is a dummyNode at the beginning of a queue //first of both queues are dummies if ((queueLeft.First<Node>() == dummyLeft) && (queueRight.First<Node>() == dummyRight)) { //if maxDepth of a side is reached and there is a dummy, one level is totaly searched if (depthLeft == maxDepthLeft && depthRight == maxDepthRight) { ////_Logger.Info("going deeper in the dungeon on the left side.. current level: " + depthLeft); depthLeft++; ////_Logger.Info("going deeper in the dungeon on the right side.. current level: " + depthRight); depthRight++; continue; } else if (depthLeft == maxDepthLeft) { ////_Logger.Info("going deeper in the dungeon on the left side.. current level: " + depthLeft); depthLeft++; continue; } else if (depthRight == maxDepthRight) { ////_Logger.Info("going deeper in the dungeon on the right side.. current level: " + depthRight); depthRight++; continue; } //dequeue dummies queueLeft.Dequeue(); queueRight.Dequeue(); //increase depth's ////_Logger.Info("going deeper in the dungeon on the left side.. current level: " + depthLeft); depthLeft++; ////_Logger.Info("going deeper in the dungeon on the right side.. current level: " + depthRight); depthRight++; //if both queues are empty -> break loop if (queueLeft.Count == 0 && queueRight.Count == 0) { break; } //if left queue is empty enqueue right dummy and continue else if (queueLeft.Count == 0) { queueRight.Enqueue(dummyRight); continue; } //if right queue is empty enqueue left dummy and continue else if (queueRight.Count == 0) { queueLeft.Enqueue(dummyLeft); continue; } //enqueue both dummies else { queueLeft.Enqueue(dummyLeft); queueRight.Enqueue(dummyRight); } } //first of left queue is a dummy else if (queueLeft.First<Node>() == dummyLeft) { //if maxDepth of a side is reached and there is a dummy, one level is totaly searched if (depthLeft == maxDepthLeft) { //_Logger.Info("going deeper in the dungeon on the left side.. current level: " + depthLeft); depthLeft++; continue; } //dequeue dummy queueLeft.Dequeue(); //increase depth //_Logger.Info("going deeper in the dungeon on the left side.. current level: " + depthLeft); 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 else if (queueRight.First<Node>() == dummyRight) { //if maxDepth of a side is reached and there is a dummy, one level is totaly searched if (depthRight == maxDepthRight) { //_Logger.Info("going deeper in the dungeon on the right side.. current level: " + depthRight); depthRight++; continue; } //dequeue dummy queueRight.Dequeue(); //increase depth //_Logger.Info("going deeper in the dungeon on the right side.. current level: " + depthRight); 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 //get the first Object of the queue currentLeft = queueLeft.Dequeue(); //get the first Object of the queue currentRight = queueRight.Dequeue(); #endregion get first nodes of the queues #region load DBObjects //load DBObject currentDBObjectLeft = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), currentLeft.Key); if (currentDBObjectLeft.Failed()) { throw new NotImplementedException(); } //load DBObject currentDBObjectRight = myDBContext.DBObjectCache.LoadDBBackwardEdgeStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), new ObjectUUID(currentRight.Key.ToString().TrimStart())); if (currentDBObjectRight.Failed()) { throw new NotImplementedException(); } #endregion load DBObjects #region the edge and the backwardedge are existing if (currentDBObjectLeft.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager)) && currentDBObjectRight.Value.ContainsBackwardEdge(edgeKey)) { //get all referenced ObjectUUIDs using the given Edge var objectUUIDsLeft = (currentDBObjectLeft.Value.GetAttribute(myTypeAttribute.UUID) as ASetOfReferencesEdgeType).GetAllReferenceIDs(); Node currentNodeLeft; #region check left friends foreach (var dboLeft in objectUUIDsLeft) { #region if the child is the target if (dboLeft == myEnd.ObjectUUID) { //set currentLeft as parent of target target.addParent(currentLeft); #region check if already visited if (visitedNodesLeft.ContainsKey(dboLeft)) { //set currentLeft as parent visitedNodesLeft[dboLeft].addParent(currentLeft); //set currentNodeLeft as child currentLeft.addChild(visitedNodesLeft[dboLeft]); } else { //create a new node and set currentLeft = parent currentNodeLeft = new Node(dboLeft, currentLeft); //set currentNodeLeft as child of currentLeft currentLeft.addChild(currentNodeLeft); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and put node into the queue queueLeft.Enqueue(currentNodeLeft); } #endregion check if already visited #region check how much parents are searched 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, rootFriends, 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 parents are searched } #endregion if the child is the target #region already visited else if (visitedNodesLeft.ContainsKey(dboLeft)) { //set currentLeft as parent visitedNodesLeft[dboLeft].addParent(currentLeft); //set currentNodeLeft as child currentLeft.addChild(visitedNodesLeft[dboLeft]); } #endregion already visited #region set as visited else { //create a new node and set currentLeft = parent currentNodeLeft = new Node(dboLeft, currentLeft); //set currentNodeLeft as child of currentLeft currentLeft.addChild(currentNodeLeft); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and put node into the queue queueLeft.Enqueue(currentNodeLeft); } #endregion set as visited } #endregion check left friends //get all referenced ObjectUUIDs using the given Edge var objectUUIDsRight = currentDBObjectRight.Value.GetBackwardEdgeUUIDs(edgeKey); Node currentNodeRight; #region check right friends foreach (ObjectUUID dboRight in objectUUIDsRight) { #region if the child is the target if (rootFriends.Contains(dboRight)) { #region check if already visited //mark node as visited if (visitedNodesRight.ContainsKey(dboRight)) { //set found children visitedNodesRight[dboRight].addChild(currentRight); currentRight.addParent(visitedNodesRight[dboRight]); } else { //create a new node and set currentRight = child currentNodeRight = new Node(dboRight); currentNodeRight.addChild(currentRight); //set currentNodeRight as parent of current Right currentRight.addParent(currentNodeRight); //never seen before //mark the node as visited visitedNodesRight.Add(currentNodeRight.Key, currentNodeRight); //and look what comes on the next level of depth queueRight.Enqueue(currentNodeRight); } #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, rootFriends, 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(dboRight)) { //set found children visitedNodesRight[dboRight].addChild(currentRight); currentRight.addParent(visitedNodesRight[dboRight]); } #endregion already visited #region set as visited else { //create a new node and set currentRight = child currentNodeRight = new Node(dboRight); currentNodeRight.addChild(currentRight); //set currentNodeRight as parent of current Right currentRight.addParent(currentNodeRight); //never seen before //mark the node as visited visitedNodesRight.Add(currentNodeRight.Key, currentNodeRight); //and look what comes on the next level of depth queueRight.Enqueue(currentNodeRight); } #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, rootFriends, 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 (currentDBObjectLeft.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) { //get all referenced ObjectUUIDs using the given Edge var objectUUIDsLeft = (currentDBObjectLeft.Value.GetAttribute(myTypeAttribute.UUID) as ASetOfReferencesEdgeType).GetAllReferenceIDs(); Node currentNodeLeft; #region check left friends foreach (ObjectUUID dboLeft in objectUUIDsLeft) { #region if the child is the target if (dboLeft == myEnd.ObjectUUID) { target.addParent(currentLeft); #region check if already visited if (visitedNodesLeft.ContainsKey(dboLeft)) { //set currentLeft as parent visitedNodesLeft[dboLeft].addParent(currentLeft); //set currentNodeLeft as child currentLeft.addChild(visitedNodesLeft[dboLeft]); } else { //create a new node and set currentLeft = parent currentNodeLeft = new Node(dboLeft, currentLeft); //set currentNodeLeft as child of currentLeft currentLeft.addChild(currentNodeLeft); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and put node into the queue queueLeft.Enqueue(currentNodeLeft); } #endregion check if already visited #region check how much paths are searched 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, rootFriends, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else if (shortestOnly && findAll) { maxDepthLeft = depthLeft; shortestPathLength = Convert.ToByte(maxDepthLeft + maxDepthRight); } #endregion check if already visited } #endregion if the child is the target #region already visited from right side else if (visitedNodesRight.ContainsKey(dboLeft)) { //get node Node temp = visitedNodesRight[dboLeft]; //add parent new temp.addParent(currentLeft); //add as child currentLeft.addChild(temp); visitedNodesRight.Remove(temp.Key); visitedNodesRight.Add(temp.Key, temp); if (visitedNodesLeft.Remove(temp.Key)) { visitedNodesLeft.Add(temp.Key, temp); } 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, rootFriends, 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(dboLeft)) { //set found parents from left side as parents of matchNode //matchNode has now parents and children visitedNodesLeft[dboLeft].addParent(currentLeft); currentLeft.addChild(visitedNodesLeft[dboLeft]); } #endregion already visited #region set as visited else { //create a new node and set currentLeft = parent currentNodeLeft = new Node(dboLeft, currentLeft); //set currentNodeLeft as child of currentLeft currentLeft.addChild(currentNodeLeft); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and look what comes on the next level of depth queueLeft.Enqueue(currentNodeLeft); } #endregion set as visited } #endregion check left friends } #endregion only the edge exists #region only the backwardedge exists else if (currentDBObjectRight.Value.ContainsBackwardEdge(edgeKey)) { //get all referenced ObjectUUIDs using the given Edge var objectUUIDsRight = currentDBObjectRight.Value.GetBackwardEdgeUUIDs(edgeKey); Node currentNodeRight; #region check right friends foreach (ObjectUUID dboRight in objectUUIDsRight) { #region if the child is the target if (rootFriends.Contains(dboRight)) { #region check if already visited //mark node as visited if (visitedNodesRight.ContainsKey(dboRight)) { //set found children visitedNodesRight[dboRight].addChild(currentRight); currentRight.addParent(visitedNodesRight[dboRight]); } else { //create a new node and set currentRight = child currentNodeRight = new Node(dboRight); currentNodeRight.addChild(currentRight); //set currentNodeRight as parent of current Right currentRight.addParent(currentNodeRight); //never seen before //mark the node as visited visitedNodesRight.Add(currentNodeRight.Key, currentNodeRight); //and look what comes on the next level of depth queueRight.Enqueue(currentNodeRight); } #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, rootFriends, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else if (shortestOnly && findAll) { maxDepthRight = depthRight; shortestPathLength = Convert.ToByte(maxDepthLeft + maxDepthRight); } #endregion check how much paths are searched } #endregion if the child is the target #region already visited from left side else if (visitedNodesLeft.ContainsKey(dboRight)) { //get node Node temp = visitedNodesLeft[dboRight]; temp.addChild(currentRight); currentRight.addParent(temp); visitedNodesLeft.Remove(temp.Key); visitedNodesLeft.Add(temp.Key, temp); if (visitedNodesRight.Remove(temp.Key)) { visitedNodesRight.Add(temp.Key, temp); } 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, rootFriends, 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(dboRight)) { //set found children visitedNodesRight[dboRight].addChild(currentRight); currentRight.addParent(visitedNodesRight[dboRight]); } #endregion already visited #region set as visited else { //create a new node and set currentRight = child currentNodeRight = new Node(dboRight); currentNodeRight.addChild(currentRight); //set currentNodeRight as parent of currentRight currentRight.addParent(currentNodeRight); //never seen before //mark the node as visited visitedNodesRight.Add(currentNodeRight.Key, currentNodeRight); //and look what comes on the next level of depth queueRight.Enqueue(currentNodeRight); } #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<Node>().Key == null) { queueLeft.Dequeue(); //_Logger.Info("going deeper in the dungeon on the left side.. current level: " + depthLeft); depthLeft++; if (queueLeft.Count == 0) { continue; } else if (depthLeft > maxDepthLeft) { continue; } } #endregion check if first element of queue is a dummy //get the first Object of the queue Node currentLeft = queueLeft.Dequeue(); //load DBObject currentDBObjectLeft = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), currentLeft.Key); if (currentDBObjectLeft.Failed()) { throw new NotImplementedException(); } if (currentDBObjectLeft.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) { //get all referenced ObjectUUIDs using the given Edge var objectUUIDsLeft = (currentDBObjectLeft.Value.GetAttribute(myTypeAttribute.UUID) as ASetOfReferencesEdgeType).GetAllReferenceIDs(); Node currentNodeLeft; #region check left friends foreach (ObjectUUID dboLeft in objectUUIDsLeft) { #region if the child is the target if (dboLeft == myEnd.ObjectUUID) { target.addParent(currentLeft); #region check if already visited if (visitedNodesLeft.ContainsKey(dboLeft)) { //set currentLeft as parent visitedNodesLeft[dboLeft].addParent(currentLeft); //set currentNodeLeft as child currentLeft.addChild(visitedNodesLeft[dboLeft]); } else { //create a new node and set currentLeft = parent currentNodeLeft = new Node(dboLeft, currentLeft); //set currentNodeLeft as child of currentLeft currentLeft.addChild(currentNodeLeft); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and put node into the queue queueLeft.Enqueue(currentNodeLeft); } #endregion check if already visited #region check how much paths are searched 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, rootFriends, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else if (shortestOnly && findAll) { maxDepthLeft = depthLeft; shortestPathLength = Convert.ToByte(maxDepthLeft + maxDepthRight); } #endregion check how much paths are searched } #endregion if the child is the target #region already visited from right side else if (visitedNodesRight.ContainsKey(dboLeft)) { //get node Node temp = visitedNodesRight[dboLeft]; //add parent new temp.addParent(currentLeft); //add as child currentLeft.addChild(temp); visitedNodesRight.Remove(temp.Key); visitedNodesRight.Add(temp.Key, temp); if (visitedNodesLeft.Remove(temp.Key)) { visitedNodesLeft.Add(temp.Key, temp); } 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, rootFriends, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else if (shortestOnly && findAll) { maxDepthLeft = depthLeft; if (shortestPathLength < (maxDepthLeft + maxDepthRight)) { shortestPathLength = Convert.ToByte(maxDepthLeft + maxDepthRight); } } } #endregion already visited from right side #region already visited else if (visitedNodesLeft.ContainsKey(dboLeft)) { //set found parents from left side as parents of matchNode //matchNode has now parents and children visitedNodesLeft[dboLeft].addParent(currentLeft); currentLeft.addChild(visitedNodesLeft[dboLeft]); } #endregion already visited #region set as visited else { //create a new node and set currentLeft = parent currentNodeLeft = new Node(dboLeft, currentLeft); currentLeft.addChild(currentNodeLeft); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and look what comes on the next level of depth queueLeft.Enqueue(currentNodeLeft); } #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)) { //get the first Object of the queue Node currentRight; #region check if first element of the queue is a dummy //dummy if (queueRight.First<Node>().Key == null) { queueRight.Dequeue(); //_Logger.Info("going deeper in the dungeon on the right side.. current level: " + depthRight); depthRight++; if (queueRight.Count == 0) { continue; } } #endregion check if first element of the queue is a dummy currentRight = queueRight.Dequeue(); //load DBObject currentDBObjectRight = myDBContext.DBObjectCache.LoadDBBackwardEdgeStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), currentRight.Key); if (currentDBObjectRight.Failed()) { throw new NotImplementedException(); } if (currentDBObjectRight.Value.ContainsBackwardEdge(edgeKey)) { //get all referenced ObjectUUIDs using the given Edge var objectUUIDsRight = currentDBObjectRight.Value.GetBackwardEdgeUUIDs(edgeKey); Node currentNodeRight; #region check right friends foreach (ObjectUUID dboRight in objectUUIDsRight) { #region if the child is the target if (rootFriends.Contains(dboRight)) { #region check if already visited //mark node as visited if (visitedNodesRight.ContainsKey(dboRight)) { //set found children visitedNodesRight[dboRight].addChild(currentRight); currentRight.addParent(visitedNodesRight[dboRight]); } else { //create a new node and set currentRight = child currentNodeRight = new Node(dboRight); currentNodeRight.addChild(currentRight); //set currentNodeRight as parent of current Right currentRight.addParent(currentNodeRight); //never seen before //mark the node as visited visitedNodesRight.Add(currentNodeRight.Key, currentNodeRight); //and look what comes on the next level of depth queueRight.Enqueue(currentNodeRight); } #endregion check if already visited #region check how much paths are searched if (shortestOnly && !findAll) { //_Logger.Info("found shortest path..starting analyzer"); shortestPathLength = Convert.ToByte(depthLeft + depthRight); return new TargetAnalyzer(root, rootFriends, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else if (shortestOnly && findAll) { maxDepthRight = depthRight; shortestPathLength = Convert.ToByte(maxDepthLeft + maxDepthRight); } #endregion check how much paths are searched } #endregion if the child is the target #region already visited from left side else if (visitedNodesLeft.ContainsKey(dboRight)) { //get node Node temp = visitedNodesLeft[dboRight]; temp.addChild(currentRight); currentRight.addParent(temp); visitedNodesLeft.Remove(temp.Key); visitedNodesLeft.Add(temp.Key, temp); if (visitedNodesRight.Remove(temp.Key)) { visitedNodesRight.Add(temp.Key, temp); } 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, rootFriends, 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(dboRight)) { //set found children visitedNodesRight[dboRight].addChild(currentRight); currentRight.addParent(visitedNodesRight[dboRight]); } #endregion already visited #region set as visited else { //create a new node and set currentRight = child currentNodeRight = new Node(dboRight); currentNodeRight.addChild(currentRight); currentRight.addParent(currentNodeRight); //never seen before //mark the node as visited visitedNodesRight.Add(currentNodeRight.Key, currentNodeRight); //and look what comes on the next level of depth queueRight.Enqueue(currentNodeRight); } #endregion set as visited } #endregion check right friends } } #endregion only right queue contain objects #region abort loop else { break; } #endregion abort loop } } #endregion EdgeType is ASetReferenceEdgeType //check if the EdgeType is ASingleReferenceEdgeType #region EdgeType is ASingleReferenceEdgeType else if (myEdge is ASingleReferenceEdgeType) { #region initialize variables //if the maxDepth is greater then maxPathLength, then set maxDepth to maxPathLength if (myMaxDepth > myMaxPathLength) { myMaxDepth = myMaxPathLength; } //set depth for left side maxDepthLeft = myMaxDepth; #endregion initialize variables #region check if friends of root node have edge foreach (var node in visitedNodesLeft) { var dbo = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), node.Key); if (dbo.Failed()) { if (visitedNodesLeft.Count != 0) { visitedNodesLeft.Remove(node.Key); } else { throw new NotImplementedException(); } } if (!dbo.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) { if (visitedNodesLeft.Count != 0) { visitedNodesLeft.Remove(node.Key); } else { return null; } } } #endregion check if friends of root node have edge //if there is more than one object in the queue and the actual depth is less than MaxDepth while ((queueLeft.Count > 0) && (depthLeft <= maxDepthLeft)) { #region check if first element of queue is a dummy //dummy if (queueLeft.First<Node>().Key == null) { queueLeft.Dequeue(); //_Logger.Info("going deeper in the dungeon on the left side.. current level: " + depthLeft); depthLeft++; if ((queueLeft.Count == 0) || (depthLeft > maxDepthLeft)) { break; } else { queueLeft.Enqueue(dummyLeft); continue; } } #endregion check if first element of queue is a dummy #region load DBObject //get the first Object of the queue var currentLeft = queueLeft.Dequeue(); //load DBObject currentDBObjectLeft = myDBContext.DBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager), currentLeft.Key); if (currentDBObjectLeft.Failed()) { throw new NotImplementedException(); } #endregion load DBObject #region check if currentDBObjectLeft has attribute if (currentDBObjectLeft.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myDBContext.DBTypeManager))) { //get referenced ObjectUUID using the given Edge var objectUUIDsLeft = (currentDBObjectLeft.Value.GetAttribute(myTypeAttribute.UUID) as ASingleReferenceEdgeType).GetAllReferenceIDs(); Node currentNodeLeft; #region check left friend var dboLeft = objectUUIDsLeft.First(); //create a new node and set currentLeft = parent currentNodeLeft = new Node(dboLeft, currentLeft); #region if the child is the target if (currentNodeLeft.Key == myEnd.ObjectUUID) { //set currentLeft as parent of target target.addParent(currentLeft); //shortestPathLength is actual depth of left side plus 1 (because the depth starts with zero, but the pathLength with 1) shortestPathLength = Convert.ToByte(depthLeft + 1); return new TargetAnalyzer(root, rootFriends, target, shortestPathLength, shortestOnly, findAll).getPaths(); } #endregion if the child is the target #region already visited else if (visitedNodesLeft.ContainsKey(currentNodeLeft.Key)) { //set currentLeft as parent visitedNodesLeft[currentNodeLeft.Key].addParent(currentLeft); //set currentNodeLeft as child currentLeft.addChild(visitedNodesLeft[currentNodeLeft.Key]); } #endregion already visited #region set as visited else { //set currentNodeLeft as child of currentLeft currentLeft.addChild(currentNodeLeft); //never seen before //mark the node as visited visitedNodesLeft.Add(currentNodeLeft.Key, currentNodeLeft); //and put node into the queue queueLeft.Enqueue(currentNodeLeft); } #endregion set as visited #endregion check left friend } #endregion check if currentDBObjectLeft has attribute #region abort loop else { break; } #endregion abort loop } } #endregion EdgeType is ASingleReferenceEdgeType else { throw new NotImplementedException(); } #region start TargetAnalyzer if (shortestOnly && findAll) { if (shortestPathLength > myMaxPathLength) { shortestPathLength = myMaxPathLength; } return new TargetAnalyzer(root, rootFriends, target, shortestPathLength, shortestOnly, findAll).getPaths(); } else { return new TargetAnalyzer(root, rootFriends, target, myMaxPathLength, shortestOnly, findAll).getPaths(); } #endregion start TargetAnalyzer #endregion BidirectionalBFS }
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 (_StartFriends.Contains(myCurrent.Key)) { //duplicate list var temp = new List<ObjectUUID>(_TempList); //reverse because the path is calculated beginning at the target temp.Reverse(); //add completed path to result list _Paths.Add(temp); //log the path PathViewer.LogPath(temp); } foreach (Node parent in myCurrent.Parents) { //if parent node not already in actual path if (!parent.AlreadyInPath && !parent.Key.Equals(_Start.Key)) { //and MaxPathLength is not reached if (_TempList.Count < _MaxPathLength) { if (!_Done) { getPath(parent); } } } } if (_TempList.Count != 0) { //remove last node from actual path _TempList.Remove(_TempList.Last<ObjectUUID>()); //myCurrent isn't in actual path myCurrent.AlreadyInPath = false; } } return; }
public TargetAnalyzer(Node myStart, HashSet<ObjectUUID> myStartFriends, Node myEnd, byte myMaxPathLength, bool myShortestOnly, bool myFindAll) : this(myStart, myStartFriends, myEnd, myMaxPathLength) { _ShortestOnly = myShortestOnly; _FindAll = myFindAll; }