public float CalculateFlow() { // TODO: fix var activeNodes = Nodes.Where(node => node.IsActive()).ToList(); var activeEdges = Edges.Where(edge => edge.IsActive()).ToList(); var sourceNodes = Nodes.Where(node => node.Type == NodeType.NODETYPE_SOURCE).ToList(); var sinkNodes = Nodes.Where(node => node.Type == NodeType.NODETYPE_SINK).ToList(); if (!sourceNodes[0].IsActive() || !sinkNodes[0].IsActive()) { return(0); } //for each optimization, the optimized flow that passes node "x" will only come from one edge List <int>[] graph; // graph: node "x" has a list "graph[x]", and "graph[x]" stores the index(es) of edge(s) in "edgesForCalculation" that starts with node "x" graph = new List <int> [activeNodes.Count()]; for (int i = 0; i < activeNodes.Count(); i++) { graph[i] = new List <int>(); } // augment: node "x" has a float "augment[x]", and "augment[x]" stores the flow that passes node "x" during each optimization var augment = new float[activeNodes.Count()]; // previous: node "x" has a int "previous[x]", and "previous[x]" stores the index of edge in "edgesForCalculation" // from which the flow "augment[x]" comes // in other words, node "x" will always be the outlet in edgesForCalculation[previous[x]] (it is an edge) var previous = new int[activeNodes.Count()]; List <EdgeInternal> edgesForCalculation = new List <EdgeInternal>(); for (int i = 0; i < activeEdges.Count(); i++) { //for each active edge (in out capacity flow), there will also be an edge (out in capacity flow) in "edgesForCalculation" edgesForCalculation.Add(activeEdges[i]); EdgeInternal tempEdge = new EdgeInternal(activeEdges[i].Capacity, activeEdges[i].Refs.Item2, activeEdges[i].Refs.Item1); edgesForCalculation.Add(tempEdge); // for origin edge (in out capacity flow), node "in" will be the inlet of "edgesForCalculation[2*i]", and "out" will be the inlet of "edgesForCalculation[2*i+1]" // this information will be stored in "graph" var index_in = activeNodes.IndexOf(activeEdges[i].Refs.Item1); var index_out = activeNodes.IndexOf(activeEdges[i].Refs.Item2); graph[index_in].Add(2 * i); graph[index_out].Add(2 * i + 1); } float totalFlow = 0; while (true) { Array.Clear(augment, 0, augment.Length); List <int> travel = new List <int>(); // For each optimization, "travel" will store, up till now, the index(es) of the inlet node(s) in "activeNodes" of this optimization var sourceIndex = activeNodes.IndexOf(sourceNodes[0]); var sinkIndex = activeNodes.IndexOf(sinkNodes[0]); travel.Add(sourceIndex); // "source" is the first inlet node of each optimization augment[sourceIndex] = float.MaxValue; // for each optimization, the flow that passes "source" is always infinite while (travel.Any()) { int tempIndex = travel[travel.Count() - 1]; // inlet point that will be considered this time travel.RemoveAt(travel.Count() - 1); for (int i = 0; i < graph[tempIndex].Count(); ++i) // consider all the edges in which point "tempIndex" is inlet { EdgeInternal tempEdge = edgesForCalculation[graph[tempIndex][i]]; // edge that will be considered this time var tempOutIndex = activeNodes.IndexOf(tempEdge.Refs.Item2); if (augment[tempOutIndex] == 0 && tempEdge.Capacity > tempEdge.Flow) // "!augment[tempOutIndex]": the optimized augment of each node will only comes from one edge for each optimization { previous[tempOutIndex] = graph[tempIndex][i]; // "Graph[tempIndex][i]" is the index of edge from which the augment of point "tempOutIndex" comes from augment[tempOutIndex] = (augment[tempIndex] < (tempEdge.Capacity - tempEdge.Flow) ? augment[tempIndex] : (tempEdge.Capacity - tempEdge.Flow)); // "augment[tempOutIndex]" = min{augment of the inlet node, (capacity-flow) of this edge} travel.Add(tempOutIndex); // next time the node "tempOutIndex" will be the inlet that needs to be considered } } if (augment[sinkIndex] != 0) { break; // break this optimization if there is optimized augment in "sink" } } if (augment[sinkIndex] == 0) { break; // break the max flow calculation if after a thorough optimization, there is no extra augment that passes "sink" } for (int i = sinkIndex; i != sourceIndex; i = activeNodes.IndexOf(edgesForCalculation[previous[i]].Refs.Item1)) // i will be each point that this time the augment passes through { edgesForCalculation[previous[i]].Flow += augment[sinkIndex]; // "edgesForCalculation[Previous[i]]" is the edge from where the augment of node "i" comes from edgesForCalculation[previous[i] ^ 1].Flow -= augment[sinkIndex]; // "edgesForCalculation[Previous[i] ^ 1]" is the opposite edge of the previous one } totalFlow += augment[sinkIndex]; } return(totalFlow); }
public NetworkInternal(string JsonPath = "res://stgdata/demo-r.json") { this.Nodes = new List <NodeInternal>(); this.Edges = new List <EdgeInternal>(); var jsonFile = new File(); // Use Godot API to allow res:// paths. jsonFile.Open(JsonPath, File.ModeFlags.Read); var jsonString = jsonFile.GetAsText(); jsonFile.Close(); using (JsonDocument document = JsonDocument.Parse(jsonString)) { JsonElement root = document.RootElement; JsonElement sources = root.GetProperty("sources"); JsonElement sinks = root.GetProperty("sinks"); JsonElement nodes = root.GetProperty("nodes"); JsonElement edges = root.GetProperty("edges"); var numSources = sources.GetArrayLength(); var numSinks = sinks.GetArrayLength(); var numNodes = nodes.GetArrayLength(); foreach (JsonElement source in sources.EnumerateArray()) { var x = source.GetProperty("x").GetInt32(); var y = source.GetProperty("y").GetInt32(); var cost = source.GetProperty("cost").GetInt32(); var active = source.GetProperty("active").GetBoolean(); var state = active ? NodeState.NODE_ACTIVE : NodeState.NODE_INACTIVE; this.Nodes.Add(new NodeInternal(cost, state, NodeType.NODETYPE_SOURCE, x, y)); } foreach (JsonElement sink in sinks.EnumerateArray()) { var x = sink.GetProperty("x").GetInt32(); var y = sink.GetProperty("y").GetInt32(); var cost = sink.GetProperty("cost").GetInt32(); var active = sink.GetProperty("active").GetBoolean(); var state = active ? NodeState.NODE_ACTIVE : NodeState.NODE_INACTIVE; this.Nodes.Add(new NodeInternal(cost, state, NodeType.NODETYPE_SINK, x, y)); } foreach (JsonElement node in nodes.EnumerateArray()) { var x = node.GetProperty("x").GetInt32(); var y = node.GetProperty("y").GetInt32(); var cost = node.GetProperty("cost").GetInt32(); var active = node.GetProperty("active").GetBoolean(); var state = active ? NodeState.NODE_ACTIVE : NodeState.NODE_INACTIVE; this.Nodes.Add(new NodeInternal(cost, state, NodeType.NODETYPE_NORMAL, x, y)); } foreach (JsonElement edge in edges.EnumerateArray()) { var capacity = edge.GetProperty("capacity").GetInt32(); var link = edge.GetProperty("link").EnumerateArray().ToArray(); var type1 = link[0].GetProperty("type").GetString(); var idx1 = link[0].GetProperty("index").GetInt32(); var offset1 = 0; switch (type1) { case "source": offset1 = 0; break; case "sink": offset1 = numSources; break; case "node": offset1 = numSources + numSinks; break; } NodeInternal ref1 = this.Nodes[offset1 + idx1]; var type2 = link[1].GetProperty("type").GetString(); var idx2 = link[1].GetProperty("index").GetInt32(); var offset2 = 0; switch (type2) { case "source": offset2 = 0; break; case "sink": offset2 = numSources; break; case "node": offset2 = numSources + numSinks; break; } NodeInternal ref2 = this.Nodes[offset2 + idx2]; var newEdge = new EdgeInternal(capacity, ref1, ref2); this.Edges.Add(newEdge); } } }