public void TarjanStronglyConnected_Smoke_Test()
        {
            var graph = new DiGraph <char>();

            graph.AddVertex('A');
            graph.AddVertex('B');
            graph.AddVertex('C');
            graph.AddVertex('D');
            graph.AddVertex('E');
            graph.AddVertex('F');
            graph.AddVertex('G');
            graph.AddVertex('H');


            graph.AddEdge('A', 'B');
            graph.AddEdge('B', 'C');
            graph.AddEdge('C', 'A');

            graph.AddEdge('C', 'D');
            graph.AddEdge('D', 'E');

            graph.AddEdge('E', 'F');
            graph.AddEdge('F', 'G');
            graph.AddEdge('G', 'E');

            graph.AddEdge('F', 'H');

            var algorithm = new TarjansStronglyConnected <char>();

            var result = algorithm.FindStronglyConnectedComponents(graph);

            Assert.AreEqual(4, result.Count);

            var expectedResult = new List <List <char> >()
            {
                new char[] { 'H' }.ToList(),
                new char[] { 'E', 'F', 'G' }.ToList(),
                new char[] { 'D' }.ToList(),
                new char[] { 'A', 'B', 'C' }.ToList()
            };

            for (int i = 0; i < expectedResult.Count; i++)
            {
                var expectation = expectedResult[i];
                var actual      = result[i];

                Assert.IsTrue(expectation.Count == actual.Count);

                foreach (var vertex in expectation)
                {
                    Assert.IsTrue(actual.Contains(vertex));
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Breaks cycles in the graph, returning all edges that changed their orientation.
        /// </summary>
        /// <param name="graph"></param>
        /// <returns></returns>
        public List <(Operation Operation1, Operation Operation2)> BreakCycles(DiGraph <Operation> graph)
        {
            var changedOrientationEdges = new List <(Operation Operation1, Operation Operation2)>();

            var algorithm = new TarjansStronglyConnected <Operation>();

            List <List <Operation> > components;

            do
            {
                // find strongly connected components
                components = algorithm.FindStronglyConnectedComponents(graph).Where(x => x.Count > 1).ToList();
                foreach (List <Operation> component in components.AsShuffledEnumerable())
                {
                    var componentHashSet = component.ToHashSet();
                    foreach (var operation1 in component.AsShuffledEnumerable())
                    {
                        // get all neighbor operations that are in the same component
                        var neighborOperations = GetNeighborComponentOperations(graph, operation1, componentHashSet);

                        foreach (var operation2 in neighborOperations.AsShuffledEnumerable())
                        {
                            // two operations are not on the same job
                            // but are on the same machines (=> can switch their edge orientation if I need to)
                            if (operation1.JobId != operation2.JobId &&
                                operation1.MachineId == operation2.MachineId)
                            {
                                double probability = RandomizationProvider.Current.GetDouble();
                                // switch directions of edge with prob for back edge, forward edge or same level edge
                                if ((operation1.Order > operation2.Order && probability <= backEdgeBreakProbability) ||
                                    (operation1.Order < operation2.Order && probability <= forwardEdgeBreakProbability) ||
                                    (operation1.Order == operation2.Order && probability <= sameLevelEdgeBreakProbability))
                                {
                                    // switch edge orientation
                                    graph.RemoveEdge(operation1, operation2);
                                    graph.AddEdge(operation2, operation1);

                                    changedOrientationEdges.Add((operation1, operation2));
                                    goto cycleOut;
                                }
                            }
                        }
                    }
                }

                cycleOut :;
            } while (components.Count > 0);

            return(changedOrientationEdges);
        }