public void MultiThreadedSyncedGraphAccessTest() { // set up our session. Guid sessionId = Guid.NewGuid(); CQManager.ActivateCommandQueueStack(sessionId); var toTest = new DirectedGraph <int, DirectedEdge <int> >((a, b) => new DirectedEdge <int>(a, b), isCommandified: true, isSynchronized: true); for (int i = 0; i < 30; i++) { toTest.Add(new DirectedEdge <int>(i, i + 1)); toTest.Add(new DirectedEdge <int>(i + 3, i)); } var waitHandles = new WaitHandle[] { new AutoResetEvent(false), new AutoResetEvent(false) }; Exception caughtException = null; Console.WriteLine("Starting threads..."); var threadA = new Thread(() => MultiThreadedSyncedGraphAccessTest_ThreadA(toTest, waitHandles[0], (e) => caughtException = e)); var threadB = new Thread(() => MultiThreadedSyncedGraphAccessTest_ThreadB(toTest, waitHandles[1], (e) => caughtException = e)); threadA.Start(); threadB.Start(); Console.WriteLine("Threads started... waiting for handles"); WaitHandle.WaitAll(waitHandles); if (caughtException != null) { throw caughtException; } Console.WriteLine("All completed."); }
internal static DirectedGraph <Project, ProjectDependency> Parse(string solutionFilePath) { Dictionary <Project, IEnumerable <string> > projectsWithReferences = new Dictionary <Project, IEnumerable <string> >(); foreach (string projectFilePath in Directory.EnumerateFiles(Path.GetDirectoryName(solutionFilePath), "*.csproj", SearchOption.AllDirectories)) { projectsWithReferences.Add(new Project(GetProjectId(projectFilePath), GetProjectName(projectFilePath), projectFilePath), ProjectReader.GetProjectReferences(projectFilePath)); } var graph = new DirectedGraph <Project, ProjectDependency>(); Dictionary <string, Project> projects = projectsWithReferences.Keys.ToDictionary(p => p.Id, p => p); foreach (KeyValuePair <Project, IEnumerable <string> > projectsWithReference in projectsWithReferences) { graph.Add(projectsWithReference.Key); foreach (string projectReference in projectsWithReference.Value) { graph.Add(new ProjectDependency(projectsWithReference.Key, projects[GetProjectId(projectReference)])); } } return(graph); }
public static DirectedGraph <Entity> ColapseIdentifiables(DirectedGraph <Modifiable> modifiables) { DirectedGraph <Entity> result = new DirectedGraph <Entity>(modifiables.Comparer); foreach (var item in modifiables.OfType <Entity>()) { var toColapse = modifiables.IndirectlyRelatedTo(item, i => !(i is Entity)); var toColapseFriends = toColapse.SelectMany(i => modifiables.RelatedTo(i).OfType <Entity>()); result.Add(item, toColapseFriends); result.Add(item, modifiables.RelatedTo(item).OfType <Entity>()); } return(result); }
/// <summary> /// Creates and returns the dependency graph. The result will be cached. /// </summary> /// <param name="forceRecompute">Whether to force the recomputation of the dependency graph. If false, the cached graph will be used, if it has been previously computed.</param> public DirectedGraph <Type, DirectedEdge <Type> > CreateGraph(bool forceRecompute = false) { if (!forceRecompute && cachedGraph != null) { return(cachedGraph); } var graphNodes = container.Kernel.GraphNodes; var graph = new DirectedGraph <Type, DirectedEdge <Type> >(); //Build the nodes foreach (var graphNode in graphNodes) { if (graphNode is ComponentModel componentModel) { foreach (var service in componentModel.Services) { if (!graph.Contains(service)) { graph.Add(service); } } if (!graph.Contains(componentModel.Implementation)) { graph.Add(componentModel.Implementation); } } } //Build the edges foreach (var graphNode in graphNodes) { if (graphNode is ComponentModel componentModel) { foreach (var dep in componentModel.Dependencies) { foreach (var service in componentModel.Services) { graph.Add(new DirectedEdge <Type>(service, dep.TargetItemType)); } graph.Add(new DirectedEdge <Type>(componentModel.Implementation, dep.TargetItemType)); } } } cachedGraph = graph; return(graph); }
public DirectedGraph <T> Inverse() { DirectedGraph <T> result = new DirectedGraph <T>(Comparer); foreach (var item in Nodes) { result.Add(item); foreach (var related in RelatedTo(item)) { result.Add(related, item); } } return(result); }
public void IsConnected2Test() { DirectedGraph <string, DirectedEdge <string> > graph = new DirectedGraph <string, DirectedEdge <string> >(); graph.Add(new DirectedEdge <string>("A", "B")); // A->B graph.Add("C"); // lonely, non-connected vertex Assert.IsFalse(graph.IsConnected()); // Add a connected edge. DirectedEdge <string> toAdd = new DirectedEdge <string>("C", "B"); graph.Add(toAdd); Assert.IsTrue(graph.IsConnected()); }
public void GraphTestMethod4() { var g = new DirectedGraph <int>(); for (var i = 0; i < 10; i++) { g.Add(i); } Assert.IsTrue(g.Add(1, 5)); Assert.IsTrue(g.Add(1, 30)); Assert.IsTrue(g.Vertices.Contains(30)); Assert.IsFalse(g.Add(1, 30)); g.Add(1, 20, true); Assert.AreEqual(11, g.VerticesCount); Assert.AreEqual(3, g.EdgesCount); }
static void TryCacheSubTables(Type type, SchemaBuilder sb) { List <Type> relatedTypes = sb.Schema.Table(type).DependentTables() .Where(a => !a.Value.IsEnum) .Select(t => t.Key.Type).ToList(); dependencies.Add(type); inverseDependencies.Add(type); foreach (var rType in relatedTypes) { TryCacheTable(sb, rType); dependencies.Add(type, rType); inverseDependencies.Add(rType, type); } }
public void TopologicalSorterOnDirectedAcyclicGraphWhereDirectionMeansOrder() { DirectedGraph <string, DirectedEdge <string> > graph = new DirectedGraph <string, DirectedEdge <string> >(); graph.Add(new DirectedEdge <string>("A", "B")); // A->B graph.Add(new DirectedEdge <string>("A", "C")); // A->C graph.Add(new DirectedEdge <string>("B", "D")); // B->D graph.Add(new DirectedEdge <string>("C", "D")); // C->D graph.Add(new DirectedEdge <string>("D", "E")); // D->E graph.Add(new DirectedEdge <string>("H", "G")); // H->G graph.Add(new DirectedEdge <string>("G", "F")); // G->F TopologicalSorter <string, DirectedEdge <string> > sorter = new TopologicalSorter <string, DirectedEdge <string> >(graph, true); sorter.Sort(); List <string> expectedResults = new List <string>() { "H", "G", "F", "A", "C", "B", "D", "E" }; for (int i = 0; i < sorter.SortResults.Count; i++) { Assert.AreEqual(expectedResults[i], sorter.SortResults[i]); } }
public void IsConnectedTest() { DirectedGraph <string, DirectedEdge <string> > graph = new DirectedGraph <string, DirectedEdge <string> >(); graph.Add(new DirectedEdge <string>("A", "B")); // A->B graph.Add(new DirectedEdge <string>("A", "C")); // A->C graph.Add(new DirectedEdge <string>("B", "D")); // B->D graph.Add(new DirectedEdge <string>("C", "D")); // C->D graph.Add(new DirectedEdge <string>("D", "E")); // D->E Assert.IsTrue(graph.IsConnected()); // Add an un-connected edge. DirectedEdge <string> toAdd = new DirectedEdge <string>("G", "F"); graph.Add(toAdd); Assert.IsFalse(graph.IsConnected()); // Add a directed edge from F to A. toAdd = new DirectedEdge <string>("F", "A"); graph.Add(toAdd); Assert.IsTrue(graph.IsConnected()); }
public TestGraph(int count) { nodes = new Dictionary <char, Node <string, int> >(count); graph = new DirectedGraph <string, int>(); for (int i = 0; i < count; i++) { var key = (char)('A' + i); nodes.Add(key, graph.Add(key.ToString())); } }
public DirectedGraph <T> WhereEdges(Func <Edge <T>, bool> condition) { DirectedGraph <T> result = new DirectedGraph <T>(Comparer); foreach (var item in Nodes) { result.Add(item, RelatedTo(item).Where(to => condition(new Edge <T>(item, to)))); } return(result); }
/// <summary> /// Generates a random integer graph of maxSize size. Size here denotes the amount of edges, nodes may be up to /// twice that amount. /// </summary> /// <param name="maxSize">The maximum amount of edges the graph contains.</param> /// <returns>The randomly generated graph.</returns> private DirectedGraph <int, DirectedEdge <int> > GenerateRandomIntegerDirectedGraph(int maxSize) { int size = _random.Next(maxSize); // create an integer graph and set the edge producer func DirectedGraph <int, DirectedEdge <int> > graph = new DirectedGraph <int, DirectedEdge <int> >((a, b) => new DirectedEdge <int>(a, b)); for (int i = 0; i < size;) { int startNode = _random.Next(maxSize); int endNode = _random.Next(maxSize); if (!graph.ContainsEdge(startNode, endNode)) { graph.Add(startNode); graph.Add(endNode); graph.Add(new DirectedEdge <int>(startNode, endNode)); i++; } } return(graph); }
public void AsNonDirectedGraphTest() { DirectedGraph <string, DirectedEdge <string> > graph = new DirectedGraph <string, DirectedEdge <string> >(); graph.Add(new DirectedEdge <string>("A", "B")); // A->B graph.Add(new DirectedEdge <string>("A", "C")); // A->C graph.Add(new DirectedEdge <string>("B", "D")); // B->D graph.Add(new DirectedEdge <string>("C", "D")); // C->D graph.Add(new DirectedEdge <string>("D", "E")); // D->E Assert.IsTrue(graph.IsDirected); Assert.IsTrue(graph.EdgeCount == 5); NonDirectedGraph <string, NonDirectedEdge <string> > nonDirectedGraph = (NonDirectedGraph <string, NonDirectedEdge <string> >)graph.GetAsNonDirectedCopy(); Assert.IsFalse(nonDirectedGraph.IsDirected); Assert.IsTrue(nonDirectedGraph.ContainsEdge("A", "B")); Assert.IsTrue(nonDirectedGraph.ContainsEdge("B", "A")); Assert.IsTrue(nonDirectedGraph.ContainsEdge("A", "C")); Assert.IsTrue(nonDirectedGraph.ContainsEdge("C", "A")); Assert.IsTrue(nonDirectedGraph.ContainsEdge("B", "D")); Assert.IsTrue(nonDirectedGraph.ContainsEdge("D", "B")); Assert.IsTrue(nonDirectedGraph.ContainsEdge("C", "D")); Assert.IsTrue(nonDirectedGraph.ContainsEdge("D", "C")); Assert.IsTrue(nonDirectedGraph.ContainsEdge("D", "E")); Assert.IsTrue(nonDirectedGraph.ContainsEdge("E", "D")); foreach (Edge <string> edge in nonDirectedGraph.Edges) { Console.Write("\n\nEdge Start index: " + edge.StartVertex + "\tEdge End index:" + edge.EndVertex + "\n\t"); Assert.IsFalse(edge.IsDirected); } //Assert.IsTrue(nonDirectedGraph.EdgeCount == 10); }
public void TransitiveClosureCyclicTest() { var g = new DirectedGraph <int, DirectedEdge <int> >((a, b) => new DirectedEdge <int>(a, b), isCommandified: false, isSynchronized: true); g.Add(new DirectedEdge <int>(1, 2)); g.Add(new DirectedEdge <int>(2, 3)); g.Add(new DirectedEdge <int>(3, 1)); DirectedGraph <int, DirectedEdge <int> > h = g.TransitiveClosure(); Assert.AreEqual(3, h.VertexCount); Assert.AreEqual(9, h.EdgeCount); Assert.IsTrue(h.ContainsEdge(1, 2)); Assert.IsTrue(h.ContainsEdge(2, 3)); Assert.IsTrue(h.ContainsEdge(3, 1)); Assert.IsTrue(h.ContainsEdge(1, 3)); Assert.IsTrue(h.ContainsEdge(1, 1)); Assert.IsTrue(h.ContainsEdge(2, 1)); Assert.IsTrue(h.ContainsEdge(2, 2)); Assert.IsTrue(h.ContainsEdge(3, 2)); Assert.IsTrue(h.ContainsEdge(3, 3)); }
public void TransitiveClosureBasicTest() { // create an integer graph and set the edge producer func DirectedGraph <int, DirectedEdge <int> > g = new DirectedGraph <int, DirectedEdge <int> >((a, b) => new DirectedEdge <int>(a, b)); DirectedEdge <int> toAdd = new DirectedEdge <int>(1, 2); g.Add(toAdd); Assert.IsTrue(g.Contains(toAdd)); g.Add(new DirectedEdge <int>(2, 3)); g.Add(new DirectedEdge <int>(3, 4)); DirectedGraph <int, DirectedEdge <int> > h = g.TransitiveClosure(); Assert.IsTrue(h.VertexCount == 4); Assert.IsTrue(h.EdgeCount == 6); Assert.IsTrue(h.ContainsEdge(1, 2)); Assert.IsTrue(h.ContainsEdge(2, 3)); Assert.IsTrue(h.ContainsEdge(3, 4)); Assert.IsTrue(h.ContainsEdge(1, 3)); Assert.IsTrue(h.ContainsEdge(1, 4)); Assert.IsTrue(h.ContainsEdge(2, 4)); }
public void TransitiveClosureCyclicTest() { DirectedGraph <int, DirectedEdge <int> > g = new DirectedGraph <int, DirectedEdge <int> >((a, b) => new DirectedEdge <int>(a, b)); g.Add(new DirectedEdge <int>(1, 2)); g.Add(new DirectedEdge <int>(2, 3)); g.Add(new DirectedEdge <int>(3, 1)); DirectedGraph <int, DirectedEdge <int> > h = g.TransitiveClosure(); Assert.AreEqual(3, h.VertexCount); Assert.AreEqual(9, h.EdgeCount); Assert.IsTrue(h.ContainsEdge(1, 2)); Assert.IsTrue(h.ContainsEdge(2, 3)); Assert.IsTrue(h.ContainsEdge(3, 1)); Assert.IsTrue(h.ContainsEdge(1, 3)); Assert.IsTrue(h.ContainsEdge(1, 1)); Assert.IsTrue(h.ContainsEdge(2, 1)); Assert.IsTrue(h.ContainsEdge(2, 2)); Assert.IsTrue(h.ContainsEdge(3, 2)); Assert.IsTrue(h.ContainsEdge(3, 3)); }
/// <summary> /// Merges the ancestors of all nodes (recursively) if any node has multiple ancestors (i.e. multiple incoming edges). The input graph will not be mutated. /// If any nodes which are to be merged have edges between them, the merging will create loops, unless <paramref name="eliminateLoopsFromMergedNodes"/> is true. /// </summary> /// <typeparam name="TVertex">The type of the vertices.</typeparam> /// <param name="g">The graph.</param> /// <param name="eliminateLoopsFromMergedNodes">If true, any loop that would be created for a merged node due to the nodes to be merged having edges among them is removed.</param> /// <returns>The mutated input graph if there were no cycles in the original graph, and <see cref="Maybe.Nothing{T}"/> otherwise.</returns> public static Maybe <DirectedGraph <IFuncSet <TVertex>, DirectedEdge <IFuncSet <TVertex> > > > MergeAncestors <TVertex>( this DirectedGraph <TVertex, DirectedEdge <TVertex> > g, bool eliminateLoopsFromMergedNodes = false) where TVertex : IEquatable <TVertex> { var copy = new DirectedGraph <IFuncSet <TVertex>, DirectedEdge <IFuncSet <TVertex> > >(); g.Vertices.ForEach(v => copy.Add(new FuncSet <TVertex> { v })); g.Edges.ForEach(e => copy.Add(new DirectedEdge <IFuncSet <TVertex> >(new FuncSet <TVertex> { e.StartVertex }, new FuncSet <TVertex> { e.EndVertex }))); var ret = copy.MergeAncestors <DirectedGraph <IFuncSet <TVertex>, DirectedEdge <IFuncSet <TVertex> > >, IFuncSet <TVertex> >( vs => new FuncSet <TVertex>(vs.Concat()), (s, e) => new DirectedEdge <IFuncSet <TVertex> >(s, e), (xs, ys) => xs.IsSupersetOf(ys), eliminateLoopsFromMergedNodes); return(ret); }
public void TopologicalSorterOnDirectedGraphWithCycle() { DirectedGraph <string, DirectedEdge <string> > graph = new DirectedGraph <string, DirectedEdge <string> >(); graph.Add(new DirectedEdge <string>("A", "B")); // A->B graph.Add(new DirectedEdge <string>("A", "C")); // A->C graph.Add(new DirectedEdge <string>("B", "D")); // B->D graph.Add(new DirectedEdge <string>("C", "D")); // C->D graph.Add(new DirectedEdge <string>("D", "E")); // D->E graph.Add(new DirectedEdge <string>("E", "A")); // E->A, creates cycle A, B/C, D, E, A graph.Add(new DirectedEdge <string>("H", "G")); // H->G graph.Add(new DirectedEdge <string>("G", "F")); // G->F TopologicalSorter <string, DirectedEdge <string> > sorter = new TopologicalSorter <string, DirectedEdge <string> >(graph); sorter.Sort(); }
public void TestClone() { var original = new DirectedGraph <string, string>() { "a", "b", { "a", "b", "a-b" }, }; var cloned = original.Clone() as DirectedGraph <string, string>; original.Add("c"); Assert.False(cloned.Contains("c")); }
public void TopologicalSorterOnDirectedGraphWithCycle() { DirectedGraph <string, DirectedEdge <string> > graph = new DirectedGraph <string, DirectedEdge <string> >(); graph.Add(new DirectedEdge <string>("A", "B")); // A->B graph.Add(new DirectedEdge <string>("A", "C")); // A->C graph.Add(new DirectedEdge <string>("B", "D")); // B->D graph.Add(new DirectedEdge <string>("C", "D")); // C->D graph.Add(new DirectedEdge <string>("D", "E")); // D->E graph.Add(new DirectedEdge <string>("E", "A")); // E->A, creates cycle A, B/C, D, E, A graph.Add(new DirectedEdge <string>("H", "G")); // H->G graph.Add(new DirectedEdge <string>("G", "F")); // G->F TopologicalSorter <string, DirectedEdge <string> > sorter = new TopologicalSorter <string, DirectedEdge <string> >(graph); Assert.That(() => sorter.Sort(), Throws.TypeOf <InvalidOperationException>()); }
static void AssertOrder(TestGraph graph, string expected) { var order = graph.TopologicalSort(); AssertOrder(order, expected); var orderedGraph = new DirectedGraph <string, int>(); foreach (var node in order) { orderedGraph.Add(node); } var secondOrder = orderedGraph.TopologicalSort(); AssertOrder(secondOrder, expected); }
public void DikastraMinDistanceTest() { var graph = new DirectedGraph <string>(); graph.Add(new DirectedEdge <string>("B", "A", 2)); graph.Add(new DirectedEdge <string>("A", "C", 5)); graph.Add(new DirectedEdge <string>("C", "B", 15)); graph.Add(new DirectedEdge <string>("A", "D", 30)); graph.Add(new DirectedEdge <string>("B", "E", 8)); graph.Add(new DirectedEdge <string>("E", "D", 4)); graph.Add(new DirectedEdge <string>("C", "F", 7)); graph.Add(new DirectedEdge <string>("F", "E", 18)); graph.Add(new DirectedEdge <string>("F", "D", 10)); var dikastra = graph.DikastraMinDistance("A"); Assert.AreEqual(20, dikastra["B"].Distance); Assert.AreEqual(1, dikastra["B"].RouteVertexs.Count); Assert.AreEqual("C", dikastra["B"].RouteVertexs[0]); Assert.AreEqual(5, dikastra["C"].Distance); Assert.AreEqual(0, dikastra["C"].RouteVertexs.Count); Assert.AreEqual(22, dikastra["D"].Distance); Assert.AreEqual(2, dikastra["D"].RouteVertexs.Count); Assert.AreEqual("C", dikastra["D"].RouteVertexs[0]); Assert.AreEqual("F", dikastra["D"].RouteVertexs[1]); Assert.AreEqual(28, dikastra["E"].Distance); Assert.AreEqual(2, dikastra["E"].RouteVertexs.Count); Assert.AreEqual("C", dikastra["E"].RouteVertexs[0]); Assert.AreEqual("B", dikastra["E"].RouteVertexs[1]); Assert.AreEqual(12, dikastra["F"].Distance); Assert.AreEqual(1, dikastra["F"].RouteVertexs.Count); Assert.AreEqual("C", dikastra["F"].RouteVertexs[0]); }
public void TopologicalSortTest() { var graph = new DirectedGraph <string>(); graph.Add(new DirectedEdge <string>("c1", "c2")); graph.Add(new DirectedEdge <string>("c2", "c6")); graph.Add(new DirectedEdge <string>("c1", "c3")); graph.Add(new DirectedEdge <string>("c3", "c6")); graph.Add(new DirectedEdge <string>("c4", "c3")); graph.Add(new DirectedEdge <string>("c4", "c5")); graph.Add(new DirectedEdge <string>("c5", "c6")); List <string> topological; var has_loop = graph.TopologicalSort(out topological); Assert.IsFalse(has_loop); }
public void OrphanedVerticesRetrievalTest() { DirectedGraph <string, DirectedEdge <string> > graph = new DirectedGraph <string, DirectedEdge <string> >(); graph.Add(new DirectedEdge <string>("A", "B")); // A->B graph.Add(new DirectedEdge <string>("A", "C")); // A->C graph.Add(new DirectedEdge <string>("B", "D")); // B->D graph.Add(new DirectedEdge <string>("C", "D")); // C->D graph.Add(new DirectedEdge <string>("D", "E")); // D->E graph.Add(new DirectedEdge <string>("H", "G")); // H->G DirectedEdge <string> toAdd = new DirectedEdge <string>("G", "F"); graph.Add(toAdd); // G->F graph.Remove(toAdd); HashSet <string> orphanedVertices = graph.GetOrphanedVertices(); Assert.AreEqual(1, orphanedVertices.Count); Assert.IsTrue(orphanedVertices.Contains("F")); }
public void GraphTestMethod1() { var g = new DirectedGraph <int>(); for (var i = 0; i < 10; i++) { g.Add(i); } Assert.IsTrue(g.Add(1, 2)); Assert.IsTrue(g.Add(2, 3)); Assert.IsFalse(g.Add(2, 3)); Assert.IsTrue(g.Add(9, 3)); Assert.IsTrue(g.Add(7, 8)); Assert.AreEqual(10, g.VerticesCount); Assert.AreEqual(4, g.EdgesCount); }
public void RemoveOrphanedVerticesWhenEdgeIsRemovedTest() { DirectedGraph <string, DirectedEdge <string> > graph = new DirectedGraph <string, DirectedEdge <string> >(); graph.Add(new DirectedEdge <string>("A", "B")); // A->B graph.Add(new DirectedEdge <string>("A", "C")); // A->C graph.Add(new DirectedEdge <string>("B", "D")); // B->D graph.Add(new DirectedEdge <string>("C", "D")); // C->D graph.Add(new DirectedEdge <string>("D", "E")); // D->E graph.Add(new DirectedEdge <string>("H", "G")); // H->G DirectedEdge <string> toAdd = new DirectedEdge <string>("G", "F"); graph.Add(toAdd); // G->F graph.RemoveOrphanedVerticesOnEdgeRemoval = true; graph.Remove(toAdd); HashSet <string> orphanedVertices = graph.GetOrphanedVertices(); Assert.AreEqual(0, orphanedVertices.Count); Assert.IsFalse(graph.Contains("F")); }
public void CommandifiedGraphAddRemoveVertexWithUndoTest() { Guid sessionId = Guid.NewGuid(); CQManager.ActivateCommandQueueStack(sessionId); DirectedGraph <int, DirectedEdge <int> > graph = new DirectedGraph <int, DirectedEdge <int> >(true); graph.Add(42); Assert.IsTrue(graph.Contains(42)); CQManager.UndoLastCommand(); Assert.IsFalse(graph.Contains(42)); Assert.AreEqual(0, graph.VertexCount); graph.Add(42); graph.Add(13); graph.Add(10); Assert.IsTrue(graph.Contains(42)); Assert.IsTrue(graph.Contains(13)); Assert.IsTrue(graph.Contains(10)); graph.Add(new DirectedEdge <int>(42, 13)); // 42 -> 13 graph.Add(new DirectedEdge <int>(42, 10)); // 42 -> 10 Assert.AreEqual(2, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 13)); Assert.IsTrue(graph.ContainsEdge(42, 10)); graph.Remove(42); Assert.IsFalse(graph.Contains(42)); Assert.AreEqual(0, graph.EdgeCount); Assert.AreEqual(2, graph.VertexCount); // undo removal of 42. This should re-add 42, but also re-add the edges CQManager.UndoLastCommand(); Assert.AreEqual(2, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 13)); Assert.IsTrue(graph.ContainsEdge(42, 10)); Assert.IsTrue(graph.Contains(42)); CQManager.ActivateCommandQueueStack(Guid.Empty); }
public void CommandifiedGraphAddRemoveVertexWithUndoTest() { Guid sessionId = Guid.NewGuid(); CQManager.ActivateCommandQueueStack(sessionId); DirectedGraph<int, DirectedEdge<int>> graph = new DirectedGraph<int, DirectedEdge<int>>(true); graph.Add(42); Assert.IsTrue(graph.Contains(42)); CQManager.UndoLastCommand(); Assert.IsFalse(graph.Contains(42)); Assert.AreEqual(0, graph.VertexCount); graph.Add(42); graph.Add(13); graph.Add(10); Assert.IsTrue(graph.Contains(42)); Assert.IsTrue(graph.Contains(13)); Assert.IsTrue(graph.Contains(10)); graph.Add(new DirectedEdge<int>(42, 13)); // 42 -> 13 graph.Add(new DirectedEdge<int>(42, 10)); // 42 -> 10 Assert.AreEqual(2, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 13)); Assert.IsTrue(graph.ContainsEdge(42, 10)); graph.Remove(42); Assert.IsFalse(graph.Contains(42)); Assert.AreEqual(0, graph.EdgeCount); Assert.AreEqual(2, graph.VertexCount); // undo removal of 42. This should re-add 42, but also re-add the edges CQManager.UndoLastCommand(); Assert.AreEqual(2, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 13)); Assert.IsTrue(graph.ContainsEdge(42, 10)); Assert.IsTrue(graph.Contains(42)); CQManager.ActivateCommandQueueStack(Guid.Empty); }
public void CommandifiedGraphAddRemoveGraphAndEdgesWithUndoTest() { Guid sessionId = Guid.NewGuid(); CQManager.ActivateCommandQueueStack(sessionId); DirectedGraph <int, DirectedEdge <int> > graph = new DirectedGraph <int, DirectedEdge <int> >(true); graph.Add(42); graph.Add(13); graph.Add(10); graph.Add(new DirectedEdge <int>(42, 13)); // 42 -> 13 graph.Add(new DirectedEdge <int>(42, 10)); // 42 -> 10 Assert.IsTrue(graph.Contains(42)); Assert.IsTrue(graph.Contains(13)); Assert.IsTrue(graph.Contains(10)); Assert.AreEqual(2, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 13)); Assert.IsTrue(graph.ContainsEdge(42, 10)); // create graph to add to this graph. Doesn't have to be a commandified graph, as we're not rolling back the actions on that graph. DirectedGraph <int, DirectedEdge <int> > graphToAdd = new DirectedGraph <int, DirectedEdge <int> >(); graphToAdd.Add(1); graphToAdd.Add(2); graphToAdd.Add(3); graphToAdd.Add(new DirectedEdge <int>(1, 2)); // 1 -> 2 graphToAdd.Add(new DirectedEdge <int>(1, 3)); // 1 -> 3 graphToAdd.Add(new DirectedEdge <int>(2, 3)); // 2 -> 3 Assert.AreEqual(3, graphToAdd.VertexCount); Assert.AreEqual(3, graphToAdd.EdgeCount); // add this graph to the main graph. This is an undoable action. graph.Add(graphToAdd); Assert.AreEqual(6, graph.VertexCount); Assert.AreEqual(5, graph.EdgeCount); Assert.IsTrue(graph.Contains(1)); Assert.IsTrue(graph.Contains(2)); Assert.IsTrue(graph.Contains(3)); Assert.IsTrue(graph.ContainsEdge(1, 2)); Assert.IsTrue(graph.ContainsEdge(1, 3)); Assert.IsTrue(graph.ContainsEdge(2, 3)); // undo add CQManager.UndoLastCommand(); Assert.AreEqual(3, graph.VertexCount); Assert.AreEqual(2, graph.EdgeCount); Assert.IsFalse(graph.Contains(1)); Assert.IsFalse(graph.Contains(2)); Assert.IsFalse(graph.Contains(3)); Assert.IsFalse(graph.ContainsEdge(1, 2)); Assert.IsFalse(graph.ContainsEdge(1, 3)); Assert.IsFalse(graph.ContainsEdge(2, 3)); // redo CQManager.RedoLastCommand(); Assert.AreEqual(6, graph.VertexCount); Assert.AreEqual(5, graph.EdgeCount); Assert.IsTrue(graph.Contains(1)); Assert.IsTrue(graph.Contains(2)); Assert.IsTrue(graph.Contains(3)); Assert.IsTrue(graph.ContainsEdge(1, 2)); Assert.IsTrue(graph.ContainsEdge(1, 3)); Assert.IsTrue(graph.ContainsEdge(2, 3)); // remove the graph we added graph.Remove(graphToAdd); Assert.AreEqual(3, graph.VertexCount); Assert.AreEqual(2, graph.EdgeCount); Assert.IsFalse(graph.Contains(1)); Assert.IsFalse(graph.Contains(2)); Assert.IsFalse(graph.Contains(3)); Assert.IsFalse(graph.ContainsEdge(1, 2)); Assert.IsFalse(graph.ContainsEdge(1, 3)); Assert.IsFalse(graph.ContainsEdge(2, 3)); CQManager.UndoLastCommand(); Assert.AreEqual(6, graph.VertexCount); Assert.AreEqual(5, graph.EdgeCount); Assert.IsTrue(graph.Contains(1)); Assert.IsTrue(graph.Contains(2)); Assert.IsTrue(graph.Contains(3)); Assert.IsTrue(graph.ContainsEdge(1, 2)); Assert.IsTrue(graph.ContainsEdge(1, 3)); Assert.IsTrue(graph.ContainsEdge(2, 3)); DirectedEdge <int> newEdge = new DirectedEdge <int>(42, 1); // 42 -> 1 graph.Add(newEdge); Assert.AreEqual(6, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 1)); Assert.IsFalse(graph.ContainsEdge(1, 42)); CQManager.UndoLastCommand(); Assert.AreEqual(5, graph.EdgeCount); Assert.IsFalse(graph.ContainsEdge(42, 1)); CQManager.RedoLastCommand(); Assert.AreEqual(6, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 1)); graph.Remove(newEdge); Assert.AreEqual(5, graph.EdgeCount); Assert.IsFalse(graph.ContainsEdge(42, 1)); CQManager.UndoLastCommand(); Assert.AreEqual(6, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 1)); graph.Disconnect(42, 1, false); Assert.AreEqual(5, graph.EdgeCount); Assert.IsFalse(graph.ContainsEdge(42, 1)); CQManager.UndoLastCommand(); Assert.AreEqual(6, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 1)); CQManager.ActivateCommandQueueStack(Guid.Empty); }
/// <summary> /// A simple but effective linear-time heuristic constructs a vertex ordering, /// just as in the topological sort heuristic above, and deletes any arc going from right to left. /// /// This heuristic builds up the ordering from the outside in based on the in- and out-degrees of each vertex. /// - Any vertex of in-degree 0 is a source and can be placed first in the ordering. /// - Any vertex of out-degree 0 is a sink and can be placed last in the ordering, again without violating any constraints. /// - If not, we find the vertex with the maximum difference between in- and out-degree, /// and place it on the side of the permutation that will salvage the greatest number of constraints. /// Delete any vertex from the DAG after positioning it and repeat until the graph is empty. /// </summary> /// <returns></returns> public DirectedGraph <T> FeedbackEdgeSet() { DirectedGraph <T> result = new DirectedGraph <T>(Comparer); DirectedGraph <T> clone = this.Clone(); DirectedGraph <T> inv = this.Inverse(); HashSet <T> head = new HashSet <T>(); // for sources HashSet <T> tail = new HashSet <T>(); // for sinks while (clone.Count > 0) { var sinks = clone.Sinks(); if (sinks.Count() != 0) { foreach (var sink in sinks) { DirectedGraph <T> .RemoveFullNodeSymetric(clone, inv, sink); tail.Add(sink); } continue; } var sources = inv.Sinks(); if (sources.Count() != 0) { foreach (var source in sources) { DirectedGraph <T> .RemoveFullNodeSymetric(clone, inv, source); head.Add(source); } continue; } int fanInOut(T n) => clone.RelatedTo(n).Count() - inv.RelatedTo(n).Count(); MinMax <T> mm = clone.MinMaxBy(fanInOut); if (fanInOut(mm.Max) > -fanInOut(mm.Min)) { T node = mm.Max; foreach (var n in inv.RelatedTo(node)) { result.Add(node, n); } DirectedGraph <T> .RemoveFullNodeSymetric(clone, inv, node); head.Add(node); } else { T node = mm.Min; foreach (var n in clone.RelatedTo(node)) { result.Add(node, n); } DirectedGraph <T> .RemoveFullNodeSymetric(clone, inv, node); head.Add(node); } } return(result); }
public void CommandifiedGraphAddRemoveGraphAndEdgesWithUndoTest() { Guid sessionId = Guid.NewGuid(); CQManager.ActivateCommandQueueStack(sessionId); DirectedGraph<int, DirectedEdge<int>> graph = new DirectedGraph<int, DirectedEdge<int>>(true); graph.Add(42); graph.Add(13); graph.Add(10); graph.Add(new DirectedEdge<int>(42, 13)); // 42 -> 13 graph.Add(new DirectedEdge<int>(42, 10)); // 42 -> 10 Assert.IsTrue(graph.Contains(42)); Assert.IsTrue(graph.Contains(13)); Assert.IsTrue(graph.Contains(10)); Assert.AreEqual(2, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 13)); Assert.IsTrue(graph.ContainsEdge(42, 10)); // create graph to add to this graph. Doesn't have to be a commandified graph, as we're not rolling back the actions on that graph. DirectedGraph<int, DirectedEdge<int>> graphToAdd = new DirectedGraph<int, DirectedEdge<int>>(); graphToAdd.Add(1); graphToAdd.Add(2); graphToAdd.Add(3); graphToAdd.Add(new DirectedEdge<int>(1, 2)); // 1 -> 2 graphToAdd.Add(new DirectedEdge<int>(1, 3)); // 1 -> 3 graphToAdd.Add(new DirectedEdge<int>(2, 3)); // 2 -> 3 Assert.AreEqual(3, graphToAdd.VertexCount); Assert.AreEqual(3, graphToAdd.EdgeCount); // add this graph to the main graph. This is an undoable action. graph.Add(graphToAdd); Assert.AreEqual(6, graph.VertexCount); Assert.AreEqual(5, graph.EdgeCount); Assert.IsTrue(graph.Contains(1)); Assert.IsTrue(graph.Contains(2)); Assert.IsTrue(graph.Contains(3)); Assert.IsTrue(graph.ContainsEdge(1, 2)); Assert.IsTrue(graph.ContainsEdge(1, 3)); Assert.IsTrue(graph.ContainsEdge(2, 3)); // undo add CQManager.UndoLastCommand(); Assert.AreEqual(3, graph.VertexCount); Assert.AreEqual(2, graph.EdgeCount); Assert.IsFalse(graph.Contains(1)); Assert.IsFalse(graph.Contains(2)); Assert.IsFalse(graph.Contains(3)); Assert.IsFalse(graph.ContainsEdge(1, 2)); Assert.IsFalse(graph.ContainsEdge(1, 3)); Assert.IsFalse(graph.ContainsEdge(2, 3)); // redo CQManager.RedoLastCommand(); Assert.AreEqual(6, graph.VertexCount); Assert.AreEqual(5, graph.EdgeCount); Assert.IsTrue(graph.Contains(1)); Assert.IsTrue(graph.Contains(2)); Assert.IsTrue(graph.Contains(3)); Assert.IsTrue(graph.ContainsEdge(1, 2)); Assert.IsTrue(graph.ContainsEdge(1, 3)); Assert.IsTrue(graph.ContainsEdge(2, 3)); // remove the graph we added graph.Remove(graphToAdd); Assert.AreEqual(3, graph.VertexCount); Assert.AreEqual(2, graph.EdgeCount); Assert.IsFalse(graph.Contains(1)); Assert.IsFalse(graph.Contains(2)); Assert.IsFalse(graph.Contains(3)); Assert.IsFalse(graph.ContainsEdge(1, 2)); Assert.IsFalse(graph.ContainsEdge(1, 3)); Assert.IsFalse(graph.ContainsEdge(2, 3)); CQManager.UndoLastCommand(); Assert.AreEqual(6, graph.VertexCount); Assert.AreEqual(5, graph.EdgeCount); Assert.IsTrue(graph.Contains(1)); Assert.IsTrue(graph.Contains(2)); Assert.IsTrue(graph.Contains(3)); Assert.IsTrue(graph.ContainsEdge(1, 2)); Assert.IsTrue(graph.ContainsEdge(1, 3)); Assert.IsTrue(graph.ContainsEdge(2, 3)); DirectedEdge<int> newEdge = new DirectedEdge<int>(42, 1); // 42 -> 1 graph.Add(newEdge); Assert.AreEqual(6, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 1)); Assert.IsFalse(graph.ContainsEdge(1, 42)); CQManager.UndoLastCommand(); Assert.AreEqual(5, graph.EdgeCount); Assert.IsFalse(graph.ContainsEdge(42, 1)); CQManager.RedoLastCommand(); Assert.AreEqual(6, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 1)); graph.Remove(newEdge); Assert.AreEqual(5, graph.EdgeCount); Assert.IsFalse(graph.ContainsEdge(42, 1)); CQManager.UndoLastCommand(); Assert.AreEqual(6, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 1)); graph.Disconnect(42, 1, false); Assert.AreEqual(5, graph.EdgeCount); Assert.IsFalse(graph.ContainsEdge(42, 1)); CQManager.UndoLastCommand(); Assert.AreEqual(6, graph.EdgeCount); Assert.IsTrue(graph.ContainsEdge(42, 1)); CQManager.ActivateCommandQueueStack(Guid.Empty); }