/// <summary> /// Connects vertices in graph /// </summary> /// <param name="vertex1"></param> /// <param name="vertex2"></param> public void Connect(IVertex <T> vertex1, IVertex <T> vertex2) { if (vertex2.Equals(vertex1)) { throw new ArgumentException("Cant connect vertice to itself"); } if (this._vertices.Contains(vertex1) && this._vertices.Contains(vertex2)) { if (vertex1.Contains(vertex2)) { throw new ArgumentException("Vertices are already connected"); } vertex1.Connect(vertex2); EdgesCount++; } else { throw new ArgumentException("Vertices must be in graph"); } }
public static List <IVertex> Successors(this IVertex vertex) { List <IVertex> result = new List <IVertex>(); foreach (IEdge edge in vertex.Links) { var linkedObjects = edge.GetLinkedObjects(); if (linkedObjects.Count != 2) { throw new ArgumentException("Edge relationship (parameter 2) is not binary."); } IVertex v1 = linkedObjects[0] as IVertex; IVertex v2 = linkedObjects[1] as IVertex; if (v1.Equals(vertex)) { result.Add(v2); } } return(result); }
public List <Path> Dfs(IVertex src, IVertex dst) { if (src.Equals(dst)) { return(new List <Path> { new Path(this, new List <IEdge> { new Edge(-1, src, src, 0) }) }); } var lst = new List <Path>(); var queue = new Queue <QueueItem>(); queue.Enqueue(new QueueItem(src, new List <IEdge>())); while (queue.Count > 0) { var currentItem = queue.Dequeue(); foreach (var edge in currentItem.Node.Connectors) { if (!currentItem.Visited.Contains(edge)) { var visited = new List <IEdge>(currentItem.Visited) { edge }; if (edge.V2 == dst) { lst.Add(new Path(this, visited)); } else { queue.Enqueue(new QueueItem(edge.V2, visited)); } } } } return(lst); }
/// <summary> /// Return the predecessor vertices of a vertex following a given oriented binary relationship. /// </summary> /// <param name="vertex"></param> /// <param name="edgeType"></param> /// <returns></returns> public static List <IVertex> Predecessors(this IVertex vertex, OrientedBinaryEdgeTypeInfo edgeType) { List <IVertex> result = new List <IVertex>(); foreach (IEdge edge in vertex.Links) { if (edge.TypeIdentity.Equals(edgeType)) { var linkedObjects = edge.GetLinkedObjects(); if (linkedObjects.Count != 2) { throw new ArgumentException("Edge relationship (parameter 2) is not binary."); } IVertex v1 = linkedObjects[0] as IVertex; IVertex v2 = linkedObjects[1] as IVertex; if (v2.Equals(vertex)) { result.Add(v1); } } } return(result); }
protected static void MergeVertexTo(INewGraph graph, IVertex from, IVertex to) { LogTool.AssertIsFalse(from.Equals(to)); var fromNeighbors = graph.GetNeighborVertices(from as Common.IVertex).ToList(); foreach (var n in fromNeighbors) { var e = graph.GetEdge(from as Common.IVertex, n); LogTool.AssertNotNull(e); graph.Remove(e); if (n.Equals(to)) { continue; } graph.AddEdge(n, to as Common.IVertex); } graph.Remove(from as Common.IVertex); foreach (var n in fromNeighbors) { UpdateEdgeCost(graph, n as IVertex); } }
public static List <IVertex> Search(IGraph myGraph, IVertex mySource, IVertex myTarget, Func <IVertex, bool> myMatchingFunc = null) { // queue for bfs var leftQueue = new Queue <IVertex>(); var rightQueue = new Queue <IVertex>(); // store visited nodes in a hashset var visitedNodesLeft = new HashSet <IVertex>(); var visitedNodesRight = new HashSet <IVertex>(); var doMatching = myMatchingFunc != null; IVertex intersectionVertex = null; // init the queue with the source vertex mySource[PREDECESSOR_ATTRIBUTE_KEY] = null; myTarget[SUCCESSOR_ATTRIBUTE_KEY] = null; leftQueue.Enqueue(mySource); rightQueue.Enqueue(myTarget); visitedNodesLeft.Add(mySource); visitedNodesRight.Add(myTarget); IVertex currentLeftVertex = null; IVertex currentRightVertex = null; List <IVertex> result = null; while (leftQueue.Count > 0 && rightQueue.Count > 0) { currentLeftVertex = leftQueue.Dequeue(); currentRightVertex = rightQueue.Dequeue(); if (currentLeftVertex.Equals(myTarget)) { result = PathConcatenation.ConcatPath(myTarget, PREDECESSOR_ATTRIBUTE_KEY); break; } else if (currentRightVertex.Equals(mySource)) { result = PathConcatenation.ConcatPath(mySource, PREDECESSOR_ATTRIBUTE_KEY, false); break; } // check all children left foreach (var edge in currentLeftVertex.OutgoingEdges) { if (!visitedNodesLeft.Contains(edge.Target)) { edge.Target[PREDECESSOR_ATTRIBUTE_KEY] = currentLeftVertex; if (doMatching) { if (myMatchingFunc(edge.Target)) { leftQueue.Enqueue(edge.Target); edge.Target[MATCHING_ATTRIBUTE_KEY] = true; } else { edge.Target[MATCHING_ATTRIBUTE_KEY] = false; } } else { leftQueue.Enqueue(edge.Target); } visitedNodesLeft.Add(edge.Target); } } // check all parents right foreach (var edge in currentRightVertex.IncomingEdges) { if (!visitedNodesRight.Contains(edge.Source)) { edge.Source[SUCCESSOR_ATTRIBUTE_KEY] = currentRightVertex; if (doMatching) { if (myMatchingFunc(edge.Source)) { rightQueue.Enqueue(edge.Source); edge.Target[MATCHING_ATTRIBUTE_KEY] = true; } else { edge.Target[MATCHING_ATTRIBUTE_KEY] = false; } } else { rightQueue.Enqueue(edge.Source); } visitedNodesRight.Add(edge.Source); } } #region check intersect between visited nodes intersectionVertex = GetIntersectionVertex(visitedNodesLeft, visitedNodesRight, doMatching); if (intersectionVertex != null) { // got a connection between the searches List <IVertex> pathLeft = null; List <IVertex> pathRight = null; if (intersectionVertex[PREDECESSOR_ATTRIBUTE_KEY].Equals(currentLeftVertex)) { pathLeft = PathConcatenation.ConcatPath(intersectionVertex, PREDECESSOR_ATTRIBUTE_KEY); pathRight = PathConcatenation.ConcatPath((IVertex)intersectionVertex[SUCCESSOR_ATTRIBUTE_KEY], SUCCESSOR_ATTRIBUTE_KEY, false); } else { pathLeft = PathConcatenation.ConcatPath((IVertex)intersectionVertex[PREDECESSOR_ATTRIBUTE_KEY], PREDECESSOR_ATTRIBUTE_KEY); pathRight = PathConcatenation.ConcatPath(intersectionVertex, SUCCESSOR_ATTRIBUTE_KEY, false); } pathLeft.AddRange(pathRight); result = pathLeft; break; } #endregion } return(result); }
/// <summary> /// Compares vertices using <see cref="Vertex{T}.Data"/> property. /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public bool Equals(IVertex <T> x, IVertex <T> y) { return(x.Equals(y.Data)); }
/// <summary> /// Finds an efficiently directed path between specified start and destination(goal) vertices. /// </summary> /// <param name="p_start">The specific start of the search.</param> /// <param name="p_destination">The search destination.</param> /// <returns>The directed path between the specified start and destination, null if no such path exists.</returns> /// <remarks> /// <exception cref="ArgumentNullException">Start or destination is null.</exception> /// The A* search algorithm is known due its performance and accuracy. /// <para> /// https://en.wikipedia.org/wiki/A*_search_algorithm /// </para> /// </remarks> public IPath AStar(IVertex p_start, IVertex p_destination) { SearchResultPath rv = null; IApproximations approxTable = null; SearchVertex expanding = null; //current explored vertex IVertex expandingGVertex = null; //current explored vertex of the graph(cache from object expanding) string expandingName = string.Empty; //the name of the current explored vertex(cache from object expanding) Dictionary <string, byte> visited = null; //Already visited vertices, we intersted in the key only. PriorityQueue <SearchVertex> frontier = null; Dictionary <string, SearchVertex> frontierLookup = null; //Quick search if expanded vertex is in the frontier already. SearchVertex goal = null; if (null == p_start) { throw new ArgumentNullException("p_start", "Start vertex can not be null"); } else if (null == p_destination) { throw new ArgumentNullException("p_destination", "Destination vertex can not be null"); } if (p_start.Equals(p_destination)) { goal = new SearchVertex(p_start, null, 0, 0); } else { approxTable = m_graph.Approximations; frontier = new MinPriorityQueue <SearchVertex>(m_graph.Vertices.Count); frontierLookup = new Dictionary <string, SearchVertex>(); visited = new Dictionary <string, byte>(); //Initialize the frontier with our serach start SearchVertex start = new SearchVertex(p_start, null, 0, approxTable.GetH(p_start, p_destination)); frontier.Enqueue(start); frontierLookup.Add(start.Name, start); //Let's roll ... while (!frontier.IsEmpty) { //pick the best path so far, remove the vertex from the frontier and mark it as visited. expanding = frontier.Dequeue(); expandingGVertex = expanding.GraphVertex; expandingName = expandingGVertex.Name; frontierLookup.Remove(expandingName); visited.Add(expandingName, 0); //Expand ... foreach (IEdge e in expandingGVertex.OutEdges) { IVertex neighbor = e.Target; if (null == neighbor) { continue; //Dead-end } else if (visited.ContainsKey(neighbor.Name)) { continue; //We have been here before. } string neighborName = neighbor.Name; SearchVertex discovery = new SearchVertex(neighbor, expanding, e.Weight, approxTable.GetH(neighbor, p_destination)); if (neighbor.Equals(p_destination)) { //goal!! if (null == goal) { goal = discovery; } else { if (discovery.Delta < goal.Delta) { //Better path. goal = discovery; } } continue; } if (frontierLookup.ContainsKey(neighborName)) { //Still in the frontier. SearchVertex exists = frontierLookup[neighborName]; if (discovery.Delta < exists.Delta) { frontier.Remove(exists); frontierLookup.Remove(neighborName); frontier.Enqueue(discovery); frontierLookup.Add(discovery.Name, discovery); } continue; } //Don't bother if we have found a path and it is better that what we are still exploring. if (null == goal || (null != goal && discovery.Delta < goal.Delta)) { frontier.Enqueue(discovery); frontierLookup.Add(discovery.Name, discovery); } } //foreach } //while } //start != destination if (null != goal) { rv = new SearchResultPath(goal); } return(rv); }