public static void Visualize( this IGraphLayer graphLayer, Func <Operation, bool> opSelector = null, Func <Arc, bool> arcSelector = null, Func <Operation, string> additionalOpLabel = null) { GraphvizWrapper.Graph g = new GraphvizWrapper.Graph(); opSelector = opSelector ?? (x => true); arcSelector = arcSelector ?? (x => true); additionalOpLabel = additionalOpLabel ?? (x => ""); HashSet <Arc> allCriticalArcs; if (graphLayer.TimesAreUpToDate()) { allCriticalArcs = graphLayer.GetCriticalArcs(onlyDisjunctive: false).ToHashSet(); } else { allCriticalArcs = new HashSet <Arc>(); } Func <Operation, bool> opAndCriticalSelector = x => opSelector(x) || allCriticalArcs.Any(a => a.Head == x.Id || a.Tail == x.Id); Dictionary <Operation, Node> nodes = new Dictionary <Operation, Node>(); var solution = graphLayer.CostLayer.Solution; var problem = solution.Problem; var colors = ColorScale.ShuffledPalette(problem.JobCount); var connectedComponents = graphLayer.GetNonTrivialScc().SelectMany(x => x).ToHashSet(); foreach (var job in problem.Jobs) { Route route = solution.GetRoute(job); foreach (var op in route.Operations.Where(opAndCriticalSelector)) { StringBuilder label = new StringBuilder(); label.AppendLine($"id={op.Id}") .AppendLine($"time={solution.GetEntryTime(op.Id).Show()}") .AppendLine($"earliest={solution.GetOperation(op.Id).EarliestEarliestEntry.Show()}") .AppendLine($"latest={solution.GetOperation(op.Id).LatestEntry.Show()}"); if (op.DelayWeight > 0) { label.AppendLine($"weight={op.DelayWeight}"); if (graphLayer.CostLayer.GetCostAtOperation(op.Id) > 0) { label.AppendLine($"cost={Math.Round(graphLayer.CostLayer.GetCostAtOperation(op.Id))}"); } } var additional = additionalOpLabel(op); if (!string.IsNullOrWhiteSpace(additional)) { label.AppendLine(additional); } if (graphLayer.OutgoingArcs(op.Id).Where(arcSelector).Any() || graphLayer.IncomingArcs(op.Id).Where(arcSelector).Any()) { var n = new Node() { Label = label.ToString(), Shape = NodeShape.Box, FillColor = colors[job.Id], Style = NodeStyle.Filled, FontColor = connectedComponents.Contains(op.Id)? Color.Red : Color.Black }; nodes.Add(op, n); } } } g.AddNodes(nodes.Values); Console.WriteLine($"Nodes added."); foreach (var arc in Enumerable.Range(0, graphLayer.Count) .SelectMany(graphLayer.OutgoingArcs) .Where(arcSelector)) { if (nodes.TryGetValue(solution.GetOperation(arc.Tail), out var n0) && nodes.TryGetValue(solution.GetOperation(arc.Head), out var n1)) { var label = (arc.MachineId != -1 ? $"M={arc.MachineId} " : "") + $"t={arc.Length.Show()}"; var edge = new Edge(n0, n1) { Label = label, Style = arc.MachineId == -1 ? EdgeStyle.Solid : EdgeStyle.Dashed, Color = allCriticalArcs.Contains(arc) ? Color.Red : Color.Black, }; if (solution.GetEntryTime(arc.Tail) + arc.Length == solution.GetEntryTime(arc.Head)) { edge.Style = EdgeStyle.Bold; } g.AddEdges(edge); } } Console.WriteLine($"Edges added."); g.Display(); Console.WriteLine("Done."); }