public IEnumerable <TEdge> GetIncomingEdges(TVertex vertex)
 {
     if (!IncomingEdges.ContainsKey(vertex))
     {
         return(Enumerable.Empty <TEdge>());
     }
     return(IncomingEdges[vertex].SelectMany(v => v.Value));
 }
Beispiel #2
0
 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);
 }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        /// <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);
        }