public IEnumerable <TEdge> GetIncomingEdges(TVertex vertex) { if (!IncomingEdges.ContainsKey(vertex)) { return(Enumerable.Empty <TEdge>()); } return(IncomingEdges[vertex].SelectMany(v => v.Value)); }
/// <summary> /// Gets the incoming edges to a key, regardless if the node has been added or not. /// </summary> public List <TKey> GetIncoming(TKey key) { if (!IncomingEdges.TryGetValue(key, out HashSet <TKey> edges)) { return(new List <TKey>()); } return(edges.ToList()); }
/// <summary> /// Removes all edges from this vertex and removes it from the graph. /// </summary> /// <returns>This</returns> public Vertex <T> Remove() { IncomingEdges.ForEach(x => x.Remove()); OutgoingEdges.ForEach(x => x.Remove()); IncomingEdges.Clear(); OutgoingEdges.Clear(); Graph.Vertices.Remove(this); return(this); }
public void RemoveZeroDegreeNodes() { var toDelete = OutgoingEdges.Keys.Where(vertex => !OutgoingEdges[vertex].Any() && !IncomingEdges[vertex].Any()); foreach (var vertex in toDelete) { OutgoingEdges.Remove(vertex); IncomingEdges.Remove(vertex); } }
private IDictionary <TVertex, IList <TEdge> > GetIncomingEdgesMap(TVertex vertex) { if (IncomingEdges.TryGetValue(vertex, out var map)) { return(map); } map = InnerMap; OutgoingEdges[vertex] = InnerMap; IncomingEdges[vertex] = map; return(map); }
public void AddEdge(ref FlowEdge edge) { if (Index == edge.From) { OutcomingEdges.Add(edge); } if (Index == edge.To) { IncomingEdges.Add(edge); } }
/// <summary> /// Removes the edge. /// </summary> /// <param name="edge">The edge.</param> /// <returns>This</returns> public Vertex <T> RemoveEdge(Edge <T> edge) { if (edge.Sink == this) { IncomingEdges.Remove(edge); } else { OutgoingEdges.Remove(edge); } return(this); }
/// <summary> /// Removes all edges from this vertex and removes it from the graph. /// </summary> /// <returns>This</returns> public Vertex <T> Remove() { for (var x = 0; x < IncomingEdges.Count; ++x) { IncomingEdges[x].Remove(); } for (var x = 0; x < OutgoingEdges.Count; ++x) { OutgoingEdges[x].Remove(); } IncomingEdges.Clear(); OutgoingEdges.Clear(); Graph.Vertices.Remove(this); return(this); }
public bool RemoveVertex(TVertex vertex) { if (!OutgoingEdges.ContainsKey(vertex)) { return(false); } foreach (var other in OutgoingEdges[vertex].Keys) { IncomingEdges[other].Remove(vertex); } foreach (var other in IncomingEdges[vertex].Keys) { OutgoingEdges[other].Remove(vertex); } OutgoingEdges.Remove(vertex); IncomingEdges.Remove(vertex); return(true); }
public bool RemoveEdges(TVertex source, TVertex dest) { if (!OutgoingEdges.ContainsKey(source)) { return(false); } if (!IncomingEdges.ContainsKey(dest)) { return(false); } if (!OutgoingEdges[source].ContainsKey(dest)) { return(false); } OutgoingEdges[source].Remove(dest); IncomingEdges[dest].Remove(source); return(true); }
private void AddEdges(TKey key, IList <TKey> outgoing) { OutgoingEdges.Add(key, new HashSet <TKey>(outgoing)); foreach (var dest in outgoing) { if (!IncomingEdges.TryGetValue(dest, out HashSet <TKey> incoming)) { IncomingEdges[dest] = new HashSet <TKey> { key } } ; else { incoming.Add(key); } } }
public bool SearchIncomingEdges(Edge e, out Edge eli, out Edge eri) { if (IncomingEdges.SearchLeftRight(e, out eli, out eri)) { return(true); } // Try to mimic a cyclical edge list if (eli == null) { eli = IncomingEdges.Last; } if (eri == null) { eri = IncomingEdges.First; } return(false); }
public bool RemoveEdge(TVertex source, TVertex dest, TEdge data) { if (!OutgoingEdges.ContainsKey(source)) { return(false); } if (!IncomingEdges.ContainsKey(dest)) { return(false); } if (!OutgoingEdges[source].ContainsKey(dest)) { return(false); } bool foundOut = OutgoingEdges.ContainsKey(source) && OutgoingEdges[source].ContainsKey(dest) && OutgoingEdges[source][dest].Remove(data); bool foundIn = IncomingEdges.ContainsKey(dest) && IncomingEdges[dest].ContainsKey(source) && IncomingEdges[dest][source].Remove(data); if (foundOut && !foundIn) { throw new Exception("Edge found in outgoing but not incoming"); // TODO: Specialized Exception } if (foundIn && !foundOut) { throw new Exception("Edge found in incoming but not outgoing"); // TODO: Specialized Exception } if (OutgoingEdges.ContainsKey(source) && (!OutgoingEdges[source].ContainsKey(dest) || OutgoingEdges[source][dest].Count == 0)) { OutgoingEdges[source].Remove(dest); } if (IncomingEdges.ContainsKey(dest) && (!IncomingEdges[dest].ContainsKey(source) || IncomingEdges[dest][source].Count == 0)) { IncomingEdges[dest].Remove(source); } return(foundOut); }
/// <summary> /// Checks if adding the node causes a cycle. /// </summary> public Boolean CausesCycle(TKey key, IList <TKey> outgoing) { if (outgoing.Contains(key)) { return(true); // Self cycle } if (!IncomingEdges.TryGetValue(key, out HashSet <TKey> incoming) || incoming.Count == 0) { return(false); // No incoming edges, so we can't have a cycle. } // If a path exists from any outgoing edge to any incoming edge, adding the node will cause a cycle. foreach (TKey start in outgoing) { foreach (TKey end in incoming) { if (PathExists(start, end)) { return(true); } } } return(false); }
/// <summary> /// Creates a shallow copy of the graph, referencing the same keys and data as the original. /// </summary> /// <returns>A shallow copy of the original.</returns> public Graph <TKey, TData> Clone() => new Graph <TKey, TData> ( new Dictionary <TKey, TData>(Data), IncomingEdges.ToDictionary(kvp => kvp.Key, kvp => new HashSet <TKey>(kvp.Value)), OutgoingEdges.ToDictionary(kvp => kvp.Key, kvp => new HashSet <TKey>(kvp.Value)) );
public void Clear() { IncomingEdges.Clear(); OutgoingEdges.Clear(); }
public IEnumerable <TVertex> GetParents(TVertex vertex) => IncomingEdges.TryGetValue(vertex, out var parentMap) ? parentMap.Keys : Enumerable.Empty <TVertex>();
public bool Remove(DirectedEdge <T, DirectedVertex <T> > edge) { return(IncomingEdges.Remove(edge) | OutgoingEdges.Remove(edge)); }
public void AddIncoming <TV>(DirectedEdge <T, TV> edge) where TV : DirectedVertex <T> { IncomingEdges.Add((IEdge <T, DirectedVertex <T> >)edge); }
/// <summary> /// Returns the nodes topologically sorted into layers. Nodes with no outgoing edges are in the first layer, /// while nodes that only point to nodes in the first layer are in the second layer, and so on. Any node that /// points to a node that has not been added to the graph is considered detached. /// </summary> /// <returns>A tuple containing a list of layers and a list of detached keys.</returns> public (List <List <TKey> > layers, List <TKey> detached) TopologicalSort() { // This method could probably be optimized significantly. // Now that I know it's called a topological sort, could use Kahn's algorithm. // However, we'll still need to take into account detached nodes where the nodes they point // to don't actually exist. List <List <TKey> > layers = new List <List <TKey> > { new List <TKey>() }; List <TKey> detached = new List <TKey>(); foreach (var kvp in OutgoingEdges) { TKey key = kvp.Key; HashSet <TKey> destinations = OutgoingEdges[key]; if (OutgoingEdges[key].Count == 0) { layers[0].Add(key); // If a key has no outgoing edges, it's added to the first layer } else if (destinations.Any(dest => !OutgoingEdges.ContainsKey(dest))) { detached.Add(key); // If a key has any outgoing edges that are not in the graph, it is considered detached. } } HashSet <TKey> satisfiedKeys = new HashSet <TKey>(layers[0]); HashSet <TKey> unsatisfiedKeys = new HashSet <TKey>(); while (layers[layers.Count - 1].Count > 0) { IEnumerable <TKey> candidates = layers[layers.Count - 1] .SelectMany(previous => IncomingEdges.ContainsKey(previous) ? IncomingEdges[previous] : new HashSet <TKey>()) .Where(key => OutgoingEdges.ContainsKey(key)) .Concat(unsatisfiedKeys) .Distinct(); unsatisfiedKeys.Clear(); List <TKey> currentLevel = new List <TKey>(); foreach (TKey candidate in candidates) { Boolean satisfied = true; foreach (TKey outgoing in OutgoingEdges[candidate]) { // Check if each of the outgoing keys have been set already. if (satisfiedKeys.Contains(outgoing)) { continue; } // If not, then the candidate gets bumped up to the next level. satisfied = false; break; } if (!satisfied) { unsatisfiedKeys.Add(candidate); continue; } currentLevel.Add(candidate); } layers.Add(currentLevel); foreach (var key in currentLevel) { satisfiedKeys.Add(key); } } layers.RemoveAt(layers.Count - 1); detached.AddRange(unsatisfiedKeys); return(layers, detached); }