// Returns a negative cycle on the graph, if it exists. // Judicious choice of this cycle is the main way to get asymptotic speed-up. // Current implementation: Application of Bellman-Ford shortest path algorithm. public static Tuple <List <Edge>, long> FindNegativeCycle(CirculationGraph graph) { // First reset the metadata associated with this algorithm. foreach (Node n in graph.Nodes) { n.MetaData = new NodeMetaData(); } // Decide which edges should even be considered for increasing flow by those with positive Free space. List <Edge> viableEdges = new List <Edge>(); foreach (Edge e in graph.Edges) { if (e.Free > 0) { viableEdges.Add(e); } } // Iterate Bellman-Ford n-1 times. for (int i = 0; i < graph.Nodes.Count - 1; i++) { foreach (Edge e in viableEdges) { if (e.Target.MetaData.Distance > e.Source.MetaData.Distance + e.Cost) { e.Target.MetaData.Distance = e.Source.MetaData.Distance + e.Cost; e.Target.MetaData.PredEdge = e; } } } // Iterate over all edges one last time to find negative cycles. foreach (Edge e in viableEdges) { if (e.Target.MetaData.Distance > e.Source.MetaData.Distance + e.Cost) { return(FindBellmanFordCycle(e.Source)); } } // Return a null cycle if no negative cycles are found; signals that there are no more negative cycles. return(Tuple.Create <List <Edge>, long>(null, 0)); }
// Changes graph state into a minimum-cost circulation, if it exists. public static void FindMinCostCirculation(CirculationGraph graph, int smoothingIterations = -1) { int numIterations = 0; // Represent a cycle as a tuple of the edges on the cycle and the minimum free capacity. Tuple <List <Edge>, long> cycle = FindNegativeCycle(graph); while (cycle.Item1 != null && numIterations != smoothingIterations) { // Force flow equal to the minimum free capacity through all the edges on the negative cycle. foreach (Edge e in cycle.Item1) { e.AddFlow(cycle.Item2); } // Ensure that our new flow does not violate any flow conditions. graph.CheckConsistentCirculation(); cycle = FindNegativeCycle(graph); numIterations++; } }