static void Main(string[] args) { GAMSWorkspace ws; if (Environment.GetCommandLineArgs().Length > 1) { ws = new GAMSWorkspace(systemDirectory: Environment.GetCommandLineArgs()[1]); } else { ws = new GAMSWorkspace(); } GAMSJob data = ws.AddJobFromString(GetDataText()); GAMSOptions optData = ws.AddOptions(); optData.Defines.Add("useBig", "1"); optData.Defines.Add("nrScen", "100"); data.Run(optData); optData.Dispose(); GAMSParameter scenarioData = data.OutDB.GetParameter("ScenarioData"); GAMSOptions opt = ws.AddOptions(); opt.Defines.Add("datain", data.OutDB.Name); int maxiter = 40; opt.Defines.Add("maxiter", maxiter.ToString()); opt.AllModelTypes = "cplexd"; GAMSCheckpoint cpMaster = ws.AddCheckpoint(); GAMSCheckpoint cpSub = ws.AddCheckpoint(); ws.AddJobFromString(GetMasterText()).Run(opt, cpMaster, data.OutDB); GAMSModelInstance masteri = cpMaster.AddModelInstance(); GAMSParameter cutconst = masteri.SyncDB.AddParameter("cutconst", 1, "Benders optimality cut constant"); GAMSParameter cutcoeff = masteri.SyncDB.AddParameter("cutcoeff", 2, "Benders optimality coefficients"); GAMSVariable theta = masteri.SyncDB.AddVariable("theta", 0, VarType.Free, "Future profit function variable"); GAMSParameter thetaFix = masteri.SyncDB.AddParameter("thetaFix", 0, ""); masteri.Instantiate("masterproblem max zmaster using lp", opt, new GAMSModifier(cutconst), new GAMSModifier(cutcoeff), new GAMSModifier(theta, UpdateAction.Fixed, thetaFix)); ws.AddJobFromString(GetSubText()).Run(opt, cpSub, data.OutDB); int numThreads = 2; GAMSModelInstance[] subi = new GAMSModelInstance[numThreads]; Queue <Tuple <string, double, Dictionary <string, double> > > demQueue = new Queue <Tuple <string, double, Dictionary <string, double> > >(); for (int i = 0; i < numThreads; i++) { subi[i] = cpSub.AddModelInstance(); GAMSParameter received = subi[i].SyncDB.AddParameter("received", 1, "units received from first stage solution"); GAMSParameter demand = subi[i].SyncDB.AddParameter("demand", 1, "stochastic demand"); subi[i].Instantiate("subproblem max zsub using lp", opt, new GAMSModifier(received), new GAMSModifier(demand)); } opt.Dispose(); double lowerbound = double.NegativeInfinity, upperbound = double.PositiveInfinity, objmaster = double.PositiveInfinity; int iter = 1; do { Console.WriteLine("Iteration: " + iter); // Solve master if (1 == iter) // fix theta for first iteration { thetaFix.AddRecord().Value = 0; } else { thetaFix.Clear(); } masteri.Solve(GAMSModelInstance.SymbolUpdateType.BaseCase); Console.WriteLine(" Master " + masteri.ModelStatus + " : obj=" + masteri.SyncDB.GetVariable("zmaster").FirstRecord().Level); if (1 < iter) { upperbound = masteri.SyncDB.GetVariable("zmaster").FirstRecord().Level; } objmaster = masteri.SyncDB.GetVariable("zmaster").FirstRecord().Level - theta.FirstRecord().Level; foreach (GAMSSetRecord s in data.OutDB.GetSet("s")) { Dictionary <string, double> demDict = new Dictionary <string, double>(); foreach (GAMSSetRecord j in data.OutDB.GetSet("j")) { demDict[j.Keys[0]] = scenarioData.FindRecord(s.Keys[0], j.Keys[0]).Value; } demQueue.Enqueue(new Tuple <string, double, Dictionary <string, double> >(s.Keys[0], scenarioData.FindRecord(s.Keys[0], "prob").Value, demDict)); } for (int i = 0; i < numThreads; i++) { subi[i].SyncDB.GetParameter("received").Clear(); } foreach (GAMSVariableRecord r in masteri.SyncDB.GetVariable("received")) { cutcoeff.AddRecord(iter.ToString(), r.Keys[0]); for (int i = 0; i < numThreads; i++) { subi[i].SyncDB.GetParameter("received").AddRecord(r.Keys).Value = r.Level; } } cutconst.AddRecord(iter.ToString()); double objsubsum = 0.0; // solve multiple model instances in parallel Object queueMutex = new Object(); Object ioMutex = new Object(); double[] objsub = new double[numThreads]; Dictionary <string, double>[] coef = new Dictionary <string, double> [numThreads]; double[] cons = new double[numThreads]; for (int i = 0; i < numThreads; i++) { coef[i] = new Dictionary <string, double>(); foreach (GAMSSetRecord j in data.OutDB.GetSet("j")) { coef[i].Add(j.Keys[0], 0.0); } } Parallel.For(0, numThreads, delegate(int i) { ScenSolve(subi[i], ref cons[i], ref coef[i], demQueue, ref objsub[i], queueMutex, ioMutex); }); for (int i = 0; i < numThreads; i++) { objsubsum += objsub[i]; cutconst.FindRecord(iter.ToString()).Value += cons[i]; foreach (GAMSSetRecord j in data.OutDB.GetSet("j")) { cutcoeff.FindRecord(iter.ToString(), j.Keys[0]).Value += coef[i][j.Keys[0]]; } } lowerbound = Math.Max(lowerbound, objmaster + objsubsum); iter++; if (iter == maxiter + 1) { throw new Exception("Benders out of iterations"); } Console.WriteLine(" lowerbound: " + lowerbound + " upperbound: " + upperbound + " objmaster: " + objmaster); } while ((upperbound - lowerbound) >= 0.001 * (1 + Math.Abs(upperbound))); masteri.Dispose(); foreach (GAMSModelInstance inst in subi) { inst.Dispose(); } }
static void Main(string[] args) { GAMSWorkspace ws; if (Environment.GetCommandLineArgs().Length > 1) { ws = new GAMSWorkspace(systemDirectory: Environment.GetCommandLineArgs()[1]); } else { ws = new GAMSWorkspace(); } GAMSJob data = ws.AddJobFromString(GetDataText()); GAMSOptions optData = ws.AddOptions(); optData.Defines.Add("useBig", "1"); optData.Defines.Add("nrScen", "100"); data.Run(optData); optData.Dispose(); GAMSParameter scenarioData = data.OutDB.GetParameter("ScenarioData"); GAMSOptions opt = ws.AddOptions(); opt.Defines.Add("datain", data.OutDB.Name); int maxiter = 40; opt.Defines.Add("maxiter", maxiter.ToString()); opt.AllModelTypes = "cplexd"; GAMSCheckpoint cpMaster = ws.AddCheckpoint(); GAMSCheckpoint cpSub = ws.AddCheckpoint(); ws.AddJobFromString(GetMasterText()).Run(opt, cpMaster, data.OutDB); GAMSModelInstance masteri = cpMaster.AddModelInstance(); GAMSParameter cutconst = masteri.SyncDB.AddParameter("cutconst", 1, "Benders optimality cut constant"); GAMSParameter cutcoeff = masteri.SyncDB.AddParameter("cutcoeff", 2, "Benders optimality coefficients"); GAMSVariable theta = masteri.SyncDB.AddVariable("theta", 0, VarType.Free, "Future profit function variable"); GAMSParameter thetaFix = masteri.SyncDB.AddParameter("thetaFix", 0, ""); masteri.Instantiate("masterproblem max zmaster using lp", opt, new GAMSModifier(cutconst), new GAMSModifier(cutcoeff), new GAMSModifier(theta, UpdateAction.Fixed, thetaFix)); ws.AddJobFromString(GetSubText()).Run(opt, cpSub, data.OutDB); GAMSModelInstance subi = cpSub.AddModelInstance(); GAMSParameter received = subi.SyncDB.AddParameter("received", 1, "units received from master"); GAMSParameter demand = subi.SyncDB.AddParameter("demand", 1, "stochastic demand"); subi.Instantiate("subproblem max zsub using lp", opt, new GAMSModifier(received), new GAMSModifier(demand)); opt.Dispose(); double lowerbound = double.NegativeInfinity, upperbound = double.PositiveInfinity, objmaster = double.PositiveInfinity; int iter = 1; do { Console.WriteLine("Iteration: " + iter); // Solve master if (1 == iter) // fix theta for first iteration { thetaFix.AddRecord().Value = 0; } else { thetaFix.Clear(); } masteri.Solve(GAMSModelInstance.SymbolUpdateType.BaseCase); Console.WriteLine(" Master " + masteri.ModelStatus + " : obj=" + masteri.SyncDB.GetVariable("zmaster").FirstRecord().Level); if (1 < iter) { upperbound = masteri.SyncDB.GetVariable("zmaster").FirstRecord().Level; } objmaster = masteri.SyncDB.GetVariable("zmaster").FirstRecord().Level - theta.FirstRecord().Level; // Set received from master received.Clear(); foreach (GAMSVariableRecord r in masteri.SyncDB.GetVariable("received")) { received.AddRecord(r.Keys).Value = r.Level; cutcoeff.AddRecord(iter.ToString(), r.Keys[0]); } cutconst.AddRecord(iter.ToString()); double objsub = 0.0; foreach (GAMSSetRecord s in data.OutDB.GetSet("s")) { demand.Clear(); foreach (GAMSSetRecord j in data.OutDB.GetSet("j")) { demand.AddRecord(j.Keys).Value = scenarioData.FindRecord(s.Keys[0], j.Keys[0]).Value; } subi.Solve(GAMSModelInstance.SymbolUpdateType.BaseCase); Console.WriteLine(" Sub " + subi.ModelStatus + " : obj=" + subi.SyncDB.GetVariable("zsub").FirstRecord().Level); double probability = scenarioData.FindRecord(s.Keys[0], "prob").Value; objsub += probability * subi.SyncDB.GetVariable("zsub").FirstRecord().Level; foreach (GAMSSetRecord j in data.OutDB.GetSet("j")) { cutconst.FindRecord(iter.ToString()).Value += probability * subi.SyncDB.GetEquation("market").FindRecord(j.Keys).Marginal *demand.FindRecord(j.Keys).Value; cutcoeff.FindRecord(iter.ToString(), j.Keys[0]).Value += probability * subi.SyncDB.GetEquation("selling").FindRecord(j.Keys).Marginal; } } lowerbound = Math.Max(lowerbound, objmaster + objsub); iter++; if (iter == maxiter + 1) { throw new Exception("Benders out of iterations"); } Console.WriteLine(" lowerbound: " + lowerbound + " upperbound: " + upperbound + " objmaster: " + objmaster); } while ((upperbound - lowerbound) >= 0.001 * (1 + Math.Abs(upperbound))); masteri.Dispose(); subi.Dispose(); }
public void ProcessTask(TaskManager.TaskDetails oTask, out List <string> lsLogs, out string sOutput, out string sStatus) { // cast input values CutStockInput oInput = new CutStockInput(); oInput = (CutStockInput)oDF.XmlStringToObject(oTask.InputValues, oInput); CutStockOutput oOutput = new CutStockOutput(); // call processing algorithm GAMSWorkspace ws = new GAMSWorkspace(); lsLog.Add("working directory : " + ws.WorkingDirectory); // instantiate GAMSOptions and define parameters GAMSOptions opt = ws.AddOptions(); GAMSDatabase cutstockData = ws.AddDatabase("csdata"); opt.AllModelTypes = "Cplex"; opt.OptCR = 0.0; // Solve to optimality opt.Defines.Add("pmax", oInput.MaxPattern.ToString()); opt.Defines.Add("solveMasterAs", "RMIP"); GAMSSet widths = cutstockData.AddSet("i", 1, "widths"); GAMSParameter rawWidth = cutstockData.AddParameter("r", 0, "raw width"); GAMSParameter demand = cutstockData.AddParameter("d", 1, "demand"); GAMSParameter width = cutstockData.AddParameter("w", 1, "width"); rawWidth.AddRecord().Value = oInput.RawWidth; foreach (CutItem oI in oInput.Items) { widths.AddRecord(oI.Name); demand.AddRecord(oI.Name).Value = oI.Demand; width.AddRecord(oI.Name).Value = oI.Width; } // create initial checkpoint GAMSCheckpoint masterCP = ws.AddCheckpoint(); GAMSJob masterInitJob = ws.AddJobFromString(GetMasterModel()); masterInitJob.Run(opt, masterCP, cutstockData); GAMSJob masterJob = ws.AddJobFromString("execute_load 'csdata', aip, pp; solve master min z using %solveMasterAs%;", masterCP); GAMSSet pattern = cutstockData.AddSet("pp", 1, "pattern index"); GAMSParameter patternData = cutstockData.AddParameter("aip", 2, "pattern data"); // Initial pattern: pattern i hold width i int patternCount = 0; foreach (GAMSParameterRecord rec in width) { patternData.AddRecord(rec.Keys[0], pattern.AddRecord((++patternCount).ToString()).Keys[0]).Value = (int)(oInput.RawWidth / rec.Value); } // create model instance for sub job GAMSCheckpoint subCP = ws.AddCheckpoint(); ws.AddJobFromString(GetSubModel()).Run(opt, subCP, cutstockData); GAMSModelInstance subMI = subCP.AddModelInstance(); // define modifier demdual GAMSParameter demandDual = subMI.SyncDB.AddParameter("demdual", 1, "dual of demand from master"); subMI.Instantiate("pricing min z using mip", opt, new GAMSModifier(demandDual)); // find new pattern bool patternAdded = true; do { masterJob.Run(opt, masterCP, cutstockData); // Copy duals into gmssubMI.SyncDB DB demandDual.Clear(); foreach (GAMSEquationRecord dem in masterJob.OutDB.GetEquation("demand")) { demandDual.AddRecord(dem.Keys[0]).Value = dem.Marginal; } subMI.Solve(); if (subMI.SyncDB.GetVariable("z").FindRecord().Level < -0.00001) { if (patternCount == oInput.MaxPattern) { lsLog.Add("Out of pattern. Increase maxpattern (currently " + oInput.MaxPattern + ")." + Environment.NewLine); patternAdded = false; } else { lsLog.Add("New pattern! Value: " + subMI.SyncDB.GetVariable("z").FindRecord().Level + Environment.NewLine); GAMSSetRecord s = pattern.AddRecord((++patternCount).ToString()); foreach (GAMSVariableRecord y in subMI.SyncDB.GetVariable("y")) { if (y.Level > 0.5) { patternData.AddRecord(y.Keys[0], s.Keys[0]).Value = Math.Round(y.Level); } } } } else { patternAdded = false; } } while (patternAdded); // solve final MIP opt.Defines["solveMasterAs"] = "MIP"; masterJob.Run(opt, cutstockData); var dlevel = masterJob.OutDB.GetVariable("z").FindRecord().Level; oOutput.OptimalSolution = (int)dlevel; lsLog.Add("Optimal Solution: " + dlevel + Environment.NewLine); List <Pattern> lP = new List <Pattern>(); foreach (GAMSVariableRecord xp in masterJob.OutDB.GetVariable("xp")) { string sPatternLog = ""; if (xp.Level > 0.5) { sPatternLog = string.Format(" pattern {0,2} {1,4} times: ", xp.Keys[0], Math.Round(xp.Level)); GAMSParameterRecord aip = masterJob.OutDB.GetParameter("aip").FirstRecord(" ", xp.Keys[0]); Pattern oP = new Pattern() { Name = "pattern " + xp.Keys[0].ToString(), Count = (int)Math.Round(xp.Level) }; List <PatternPiece> lPP = new List <PatternPiece>(); int x = 0; double scale = 100 / masterJob.OutDB.GetParameter("r").FirstRecord().Value; do { sPatternLog += " " + aip.Keys[0] + ": " + aip.Value.ToString(); // draw cuts for (int i = 0; i < aip.Value; i++) { PatternPiece oPP = new PatternPiece() { Name = aip.Keys[0], Width = (int)(width.FindRecord(aip.Keys[0]).Value *scale), Left = x, Color = oInput.Items.Where(xi => xi.Name == aip.Keys[0]).FirstOrDefault().Color }; lPP.Add(oPP); // x += oPP.Width - 1; x += oPP.Width; } } while (aip.MoveNext()); if (x < 100) { PatternPiece oPExcess = new PatternPiece() { Name = "E", Width = (int)(rawWidth.FirstRecord().Value *scale - x), Left = x, Color = "CCCCCC" }; lPP.Add(oPExcess); } lsLog.Add(sPatternLog); oP.Pieces = lPP.ToArray(); lP.Add(oP); } } oOutput.Patterns = lP.ToArray(); // clean up of unmanaged resources cutstockData.Dispose(); subMI.Dispose(); opt.Dispose(); sOutput = oDF.ObjectToXmlString(oOutput); sStatus = "completed"; lsLogs = lsLog; }