void OnEnable() { frameCounter = 0; allNodesGenerated = false; node = new List <SystemNode>(); float[] prod = new float[1]; prod[0] = +1f; node.Add(new SystemNode(new Vector3(0, 0, 1), prod, 1f)); prod = new float[1]; prod[0] = -0.4f; node.Add(new SystemNode(new Vector3(-0.6f, 0, 0), prod, 1f)); prod = new float[1]; prod[0] = -0.6f; node.Add(new SystemNode(new Vector3(+0.6f, 0, 0), prod, 1f)); for (int a = 0; a < node.Count; a++) { for (int b = 0; b < node.Count; b++) { if (b != a) { node[a].AddDistanceEdge(new DistanceEdge(node[b], (node[a].pos - node[b].pos).magnitude)); } } } LinearProgrammingSolution solution = LinearProgramming.MinimumCostFlow(node); // Interpret analysis results for (int i = 0; i < solution.source.Count; i++) { solution.source[i].AddResourceEdge(new ResourceEdge(solution.target[i], solution.magnitude[i])); } }
/* * A linear programming problem is in STANDARD FORM if it seeks to MAXIMISE the objective * function z = c1x1 + c2x2 + ... + cnxn subject to the constraints: * a11x1 + a12x2 + ... + a1nxn <= b1 * a21x1 + a22x2 + ... + a2nxn <= b2 * ... ... ... ... ... * am1x1 + am2x2 + ... + amnxn <= bm * where xi >= 0 and bi >= 0. * After adding slack variables, the corresponding system of CONSTRAINT EQUATIONS is: * a11x1 + a12x2 + ... + a1nxn + s1 = b1 * a21x1 + a22x2 + ... + a2nxn + s2 = b2 * ... ... ... ... ... * am1x1 + am2x2 + ... + amnxn + sm = bm * where si >= 0. */ /* * Note that for a linear programming problem in standard form, the objective is to be * maximised, not minimised. */ /* A BASIC SOLUTION of a linear programming problem in standard form is a solution * (x1, x2, ..., xn, s1, s2, ..., sm) of the constraint equations in which AT MOST m variables * are nonzero - the variables that are nonzero are called BASIC VARIABLES. A basic solution * for which all variables are nonnegative is called a BASIC FEASIBLE SOLUTION. */ /* * The simplex method is carried out by performing elementary row operations on a matrix that * we call the SIMPLEX TABLEAU. This tableau consists of the augmented matrix corresponding * to the constraint equations together with the coefficients of the objective function written * in the form * -c1x1 - c2x2 - ... - cnxn + (0)s1 + (0)s2 + ... + (0)sm + z = 0 * In the tableau, it is customary to omit the coefficient of z. For instance, the simplex * tableau for the linear programming problem * z = 4x1 + 6x2 objective function * x1, x2 >= 0 constraint * -x1 + x2 + s1 = 11 constraint * x1 + x2 + s2 = 27 constraint * 2x1 + 5x2 + s3 = 90 constraint * is as follows. */ /* * x1 x2 s1 s2 s3 b basic variables * -1 +1 +1 0 0 11 s1 * +1 +1 0 +1 0 27 s2 * +2 +5 0 0 +1 90 s3 * --------------------------- * -4 -6 0 0 0 0 <-- current z-value */ public static LinearProgrammingSolution MinimumCostFlow(List <SystemNode> systemNode) { Debug.Log("Performing minimum-cost flow analysis."); // Take a copy of the network //List<SystemNode> copy = new List<SystemNode>(); //foreach (SystemNode n in systemNode) copy.Add(n.TakeCopy()); Debug.Log("Network copy taken."); int nSurrogate = Surrogate(systemNode); Debug.Log(nSurrogate + " surrogate nodes inserted."); // Count the number of nodes and edges int numNodes = 0; int numEdges = 0; foreach (SystemNode n in systemNode) { numNodes++; foreach (DistanceEdge d in n.distance) { numEdges++; } } Debug.Log("Number of nodes: " + numNodes); Debug.Log("Number of edges: " + numEdges); //float[,] tableau = BuildMatrix(copy, numNodes, numEdges); float[,] matrix = BuildMatrix(systemNode, numNodes, numEdges); Debug.Log("Augmented matrix constructed."); //PrintTableau(matrix); float[] rawResult = Minimise(matrix); // Interpret result float[] flows = new float[numEdges]; float cost = rawResult[rawResult.Length - 1]; for (int i = 0; i < numEdges; i++) { int index = rawResult.Length - numEdges - 1 + i; flows[i] = rawResult[index]; } // Record resource flow edge data List <SystemNode> source = new List <SystemNode>(); List <Node> target = new List <Node>(); List <float> magnitude = new List <float>(); int nodeIndex = -1; int edgeIndex = -1; foreach (SystemNode n in systemNode) { nodeIndex++; foreach (DistanceEdge d in n.distance) { edgeIndex++; if (flows[edgeIndex] > 0) { if (!n.surrogate && !d.target.surrogate) { source.Add(n); target.Add(d.target); magnitude.Add(flows[edgeIndex]); } } } } // Build solution LinearProgrammingSolution solution = new LinearProgrammingSolution(source, target, magnitude); // Destroy surrogate nodes List <int> surrogateIndex = new List <int>(); for (int i = 0; i < systemNode.Count; i++) { if (systemNode[i].surrogate) { surrogateIndex.Add(i); } } //for (int i = 0; i < surrogateIndex.Count; i++) //{ // int j = surrogateIndex.Count - 1 - i; // systemNode.RemoveAt(j); //} // Return the solution return(solution); }