public void DestroyLink(NetworkLink link) { //Console.WriteLine("Destroying link: " + link); int flowDeficit = link.flow; link.flow = 0; link.capacity = 0; // if the link wasn't flowing in the first place, there are no further steps to take. if (flowDeficit == 0) { //Console.WriteLine("The flow this link is 0, so there are no more links to reduce."); return; } //Console.WriteLine("The following links will be reduced"); // reduce the nodes in both the forward and backward directions recursively. ReduceNode(link.source, flowDeficit, false); ReduceNode(link.target, flowDeficit, true); // recalculate the maximum flow. maxFlow = target.GetFlow(false); //Console.WriteLine("Graph update complete. New max flow: " + maxFlow); }
// adds the passed node to the tables recursively static void AddNodeToTables( NetworkNode node, ref HashSet <NetworkNode> nodesAddedButNotRecorded, ref Dictionary <NetworkNode, NetworkLink> flowPathTable, ref Dictionary <NetworkNode, int> flowAmountTable, ref Stack <NetworkLink> cycleEdges ) { nodesAddedButNotRecorded.Add(node); NetworkLink bestChoice = null; int bestFlow = 0; // search the outward links for the link which offers the best path to the target. foreach (NetworkLink link in node.linksOut) { // if the link cannot pass anymore flow, skip it. if (link.capacity - link.flow == 0) { continue; } // if the target of this link has been added already, // and there is no entry for it in the flow path table, // then this is a cycle edge. Don't evaluate it now. if (nodesAddedButNotRecorded.Contains(link.target)) { cycleEdges.Push(link); continue; } else if (!flowPathTable.ContainsKey(link.target)) { AddNodeToTables(link.target, ref nodesAddedButNotRecorded, ref flowPathTable, ref flowAmountTable, ref cycleEdges); } // if the minimum between the possible increase in flow on this link // and the possible increase in flow for the path to the target // following this edge is greater than that of the other links // investigated so far, select this one as the best choice. int flow = Math.Min(link.capacity - link.flow, flowAmountTable[link.target]); if (flow > bestFlow) { bestChoice = link; bestFlow = flow; } } // add the best choice and best flow to the tables. // if there were no outward links, or all of their (capacity - flow)s were 0, bestFlow will be 0. flowPathTable.Add(node, bestChoice); flowAmountTable.Add(node, bestFlow); nodesAddedButNotRecorded.Remove(node); }
// Creates a directed network graph from a file. Automatically sets each link's capacity using an RNG. // Generates a source and target node, connecting them at maximum flow to 'K' other nodes in the graph. // fileName: name of the file containing the graph data. // vertextCount: the number of verteces contained in the file. // edgeCount: the number of edges contained in the file. // minCapacity: the minimum capacity of the links in the graph. These will be randomly generated. // maxCapacity: the maximum capacity of the links in the graph. These will be randomly generated. // K: the number of edges that the generated source and target nodes will have going into, and out of, respectfully. // SEED: the random number generator seed. public NetworkGraph(string fileName, int vertexCount, int edgeCount, int minCapacity, int maxCapacity, int K, int SEED) { Random random = new Random(SEED); vertices = new NetworkNode[vertexCount + 2]; // plus 2 for the source and target nodes that will be generated. edges = new NetworkLink[edgeCount + 2 * K]; // plus 2 * K for the K edges going into and out of the source and target. maxFlow = 0; // begin reading and parsing the file. using (Stream Stream = File.OpenRead(fileName)) using (StreamReader reader = new StreamReader(Stream)) { string[] sepNodes = { "node [", "edge [" }; //Index 0 is everything before nodes, Don't need; //Index nodes.Length is the edges, parsed after; string[] arrayStrNodes = reader.ReadToEnd().Split(sepNodes, StringSplitOptions.RemoveEmptyEntries); for (int i = 1; i < arrayStrNodes.Length; i++) { string[] arrNode = arrayStrNodes[i].Split('\n'); bool isEdge = false; int id = -1; float longitude = -1; float latitude = -1; string label = ""; int source = -1; int target = -1; for (int j = 1; j < arrNode.Length; j++) { if (arrNode[j].Length > 4) { switch (arrNode[j][4]) { case 'i': string strID = arrNode[j].Substring(7); if (strID.Length > 1 && strID[1] == 'e')//added length check for id 0 of nodes { isEdge = true; id = Convert.ToInt32(strID.Substring(2, strID.Length - 4)); } else { id = Convert.ToInt32(strID); } break; case 'L': if (arrNode[j][5] == 'o')//Longitude { longitude = (float)Convert.ToDouble(arrNode[j].Substring(14)); } else//Latitude { latitude = (float)Convert.ToDouble(arrNode[j].Substring(13)); } break; case 'l': label = arrNode[j].Substring(11, arrNode[j].Length - 13); break; case 's': source = Convert.ToInt32(arrNode[j].Substring(10)); break; case 't': target = Convert.ToInt32(arrNode[j].Substring(10)); break; } } } if (id > -1) { if (isEdge) { NetworkLink link = new NetworkLink(vertices[source], vertices[target]); edges[id] = link; link.capacity = random.Next(minCapacity, maxCapacity + 1); } else { NetworkNode node = new NetworkNode(label, longitude, latitude); vertices[id] = node; } } } } //Declaring the source and target nodes //Doesn't really matter "where" they are source = new NetworkNode("source", 0, 0); target = new NetworkNode("target", 0, 0); vertices[vertexCount] = source; vertices[vertexCount + 1] = target; Random rand = new Random(SEED); //List to keep track of the nodes that are conncected to by the source and target List <NetworkNode> sourceLinks = new List <NetworkNode>(K); List <NetworkNode> targetLinks = new List <NetworkNode>(K); //Index to keep track of where to add into the edges array int LinkIndex = 1; //generating the edges for source edges while (sourceLinks.Count < sourceLinks.Capacity) { int i = rand.Next(0, vertexCount); if (!sourceLinks.Contains(vertices[i])) { sourceLinks.Add(vertices[i]); edges[edgeCount - 1 + LinkIndex] = new NetworkLink(source, vertices[i]); edges[edgeCount - 1 + LinkIndex].capacity = 20; LinkIndex++; } } //generating edges for target edges //Compares to make sure the target does not connect to any of the same nodes as the source. while (targetLinks.Count < targetLinks.Capacity) { int i = rand.Next(0, vertexCount); if (!sourceLinks.Contains(vertices[i]) && !targetLinks.Contains(vertices[i])) { targetLinks.Add(vertices[i]); edges[edgeCount - 1 + LinkIndex] = new NetworkLink(vertices[i], target); edges[edgeCount - 1 + LinkIndex].capacity = 20; LinkIndex++; } } //Console.WriteLine("Built graph from " + fileName + ". Nodes: " + vertexCount + " Links: " + edgeCount + "."); }
static void ReduceNode(NetworkNode node, int deficit, bool forward) { // if the node has no more links to follow, just quit. if ((forward ? node.linksOut.Count : node.linksIn.Count) == 0) { return; } // try to find a link that is large enough to take the whole flow hit. // else, fill a list with links that have flow to add up to the deficit. NetworkLink toReduce = null; List <NetworkLink> reduceList = new List <NetworkLink>(); foreach (NetworkLink link in (forward ? node.linksOut : node.linksIn)) { if (link.flow == deficit) { toReduce = link; break; } else if (link.flow > deficit) { toReduce = link; } else if (link.flow != 0 && toReduce == null) { reduceList.Add(link); } } // if there is a link with an equal or greater flow than the deficit, simply reduce that one. if (toReduce != null) { //Console.WriteLine("\tReduced by " + deficit + ": " + toReduce); toReduce.flow -= deficit; ReduceNode((forward ? toReduce.target : toReduce.source), deficit, forward); } // otherwise, search through the reduce list for links that will add up their flows to the deficit and reduce each of them. else if (reduceList.Count > 0) { int i = 0; while (deficit != 0) { int flowDeficit = reduceList[i].flow; if (flowDeficit > deficit) { flowDeficit = deficit; } deficit -= flowDeficit; //Console.WriteLine("\tReduced by " + flowDeficit + ": " + reduceList[i]); reduceList[i].flow -= flowDeficit; ReduceNode((forward ? reduceList[i].target : reduceList[i].source), flowDeficit, forward); i++; } } }
// adds the network link to the correct link list. public void AddLink(NetworkLink link) { (link.source == this ? linksOut : linksIn).Add(link); }