| |||||||||||||
Goal programming Description This example tries to construct a production plan which meets four different
goals in order of priority.
Source Files By clicking on a file name, a preview is opened at the bottom of this page.
GoalProg.cs /*********************************************************************** Goal programming example ======================== An example of lexicographic goal programming using the Xpress multi-objective API. A company produces two electrical products, A and B. Both require two stages of production: wiring and assembly. The production plan must meet several goals: 1. A profit of $200 2. A contractual requirement of 40 units of product B 3. To fully utilize the available wiring department hours 4. To avoid overtime in the assembly department (c) 2022-2024 Fair Isaac Corporation ***********************************************************************/ using System; using Optimizer; namespace XPRSExamples { class GoalProg { private static readonly int COLS = 8; // Number of columns private static readonly int ROWS = 4; // Number of rows private static readonly int ENTITIES = 2; // Number of entities // Column indices private static readonly int COL_PRODUCE_A = 0; private static readonly int COL_PRODUCE_B = 1; private static readonly int COL_SURPLUS_WIRING = 2; private static readonly int COL_DEFICIT_WIRING = 3; private static readonly int COL_SURPLUS_ASSEM = 4; private static readonly int COL_DEFICIT_ASSEM = 5; private static readonly int COL_DEFICIT_PROFIT = 6; private static readonly int COL_DEFICIT_PROD_B = 7; public static void Main(string[] args) { GoalProg example = new GoalProg(); example.Run(); } private void Run() { try { XPRS.Init(""); prob = new XPRSprob(); // Tell Optimizer to call OptimizerMsg whenever a message is output prob.AddMessageCallback(new MessageCallback(this.OptimizerMsg)); // Create two integer variables and six continuous variables double[] ub = new double[8]; char[] coltype = new char[8]; int[] colind = new int[13]; for (int i = 0; i < 8; i++) { ub[i] = XPRS.PLUSINFINITY; coltype[i] = i < 2 ? 'I' : 'C'; colind[i] = i; } prob.AddCols(8, 0, new double[8], new int[8], null, null, new double[8], ub); prob.ChgColType(8, colind, coltype); // Add one row per goal int ncoef = 0; char[] rowtype = new char[4]; double[] rhs = new double[4]; int[] start = new int[4]; double[] rowcoef = new double[13]; // Goal 1: profit must meet or exceed $200 colind[ncoef] = COL_PRODUCE_A; rowcoef[ncoef++] = 7; colind[ncoef] = COL_PRODUCE_B; rowcoef[ncoef++] = 6; colind[ncoef] = COL_DEFICIT_PROFIT; rowcoef[ncoef++] = 1; rowtype[0] = 'G'; rhs[0] = 200; // Goal 2: production of product B must meet or exceed 40 units start[1] = ncoef; colind[ncoef] = COL_PRODUCE_B; rowcoef[ncoef++] = 1; colind[ncoef] = COL_DEFICIT_PROD_B; rowcoef[ncoef++] = 1; rowtype[1] = 'G'; rhs[1] = 40; // Goal 3: hours of wiring should be close to the available 120 hours start[2] = ncoef; colind[ncoef] = COL_PRODUCE_A; rowcoef[ncoef++] = 2; colind[ncoef] = COL_PRODUCE_B; rowcoef[ncoef++] = 3; colind[ncoef] = COL_SURPLUS_WIRING; rowcoef[ncoef++] = -1; colind[ncoef] = COL_DEFICIT_WIRING; rowcoef[ncoef++] = 1; rowtype[2] = 'E'; rhs[2] = 120; // Goal 4: hours of assembly should be close to the available 300 hours start[3] = ncoef; colind[ncoef] = COL_PRODUCE_A; rowcoef[ncoef++] = 6; colind[ncoef] = COL_PRODUCE_B; rowcoef[ncoef++] = 5; colind[ncoef] = COL_SURPLUS_ASSEM; rowcoef[ncoef++] = -1; colind[ncoef] = COL_DEFICIT_ASSEM; rowcoef[ncoef++] = 1; rowtype[3] = 'E'; rhs[3] = 300; prob.AddRows(4, ncoef, rowtype, rhs, start, colind, rowcoef); // Define objectives to minimize deviations, in priority order // Goal 1: minimize profit deficit prob.ChgObj(1, new int[] { COL_DEFICIT_PROFIT }, new double[] { 1 }); // Goal 2: minimize production deficit prob.ChgObjN(1, 1, new int[] { COL_DEFICIT_PROD_B }, new double[] { 1 }); // Goal 3: minimize deviation from wiring hours target prob.ChgObjN(2, 2, new int[] { COL_SURPLUS_WIRING, COL_DEFICIT_WIRING }, new double[] { 1, 1 }); // Goal 4: minimize deviation from assembly hours target prob.ChgObjN(3, 2, new int[] { COL_SURPLUS_ASSEM, COL_DEFICIT_ASSEM }, new double[] { 1, 1 }); // Set up objective priorities and tolerances for (int i = 0; i < 4; i++) { prob.SetObjIntControl(i, ObjControl.Priority, 4 - i); prob.SetObjDblControl(i, ObjControl.AbsTol, 0); prob.SetObjDblControl(i, ObjControl.RelTol, 0); } // Solve the problem prob.MipOptimize(); // Print the result if (prob.SolveStatus == SolveStatus.Completed && prob.SolStatus == SolStatus.Optimal) { double[] sol = new double[COLS]; prob.GetMipSol(sol, null); Console.WriteLine("Production plan:"); Console.WriteLine("Product A: " + ((int)sol[COL_PRODUCE_A]) + " units"); Console.WriteLine("Product B: " + ((int)sol[COL_PRODUCE_B]) + " units"); Console.WriteLine("Profit: $" + (int)(7 * sol[COL_PRODUCE_A] + 6 * sol[COL_PRODUCE_B])); if (sol[COL_DEFICIT_PROFIT] > 0) { Console.WriteLine("Profit goal missed by $" + ((int)sol[COL_DEFICIT_PROFIT])); } if (sol[COL_DEFICIT_PROD_B] > 0) { Console.WriteLine("Contractual goal for product B missed by " + ((int)sol[COL_DEFICIT_PROD_B]) + " units"); } if (sol[COL_SURPLUS_WIRING] > 0) { Console.WriteLine("Unused wiring department hours: " + ((int)sol[COL_SURPLUS_WIRING])); } if (sol[COL_DEFICIT_WIRING] > 0) { Console.WriteLine("Wiring department overtime: " + ((int)sol[COL_DEFICIT_WIRING])); } if (sol[COL_SURPLUS_ASSEM] > 0) { Console.WriteLine("Unused assembly department hours: " + ((int)sol[COL_SURPLUS_ASSEM])); } if (sol[COL_DEFICIT_ASSEM] > 0) { Console.WriteLine("Assembly department overtime: " + ((int)sol[COL_DEFICIT_ASSEM])); } } else { Console.WriteLine("Problem could not be solved"); } } catch (XPRSException e) { Console.WriteLine(e.ToString()); throw e; } finally { prob.Destroy(); XPRS.Free(); } } public void OptimizerMsg(XPRSprob prob, object data, string message, int len, int msglvl) { switch (msglvl) { case 3: case 4: Console.WriteLine("{0}" + message, data); break; } } private XPRSprob prob; } } | |||||||||||||
© Copyright 2024 Fair Isaac Corporation. |