public Cplex() { this._env = new GRBEnv("gurobi.log"); this._model = new GRBModel(_env); _model.GetEnv().Set(GRB.IntParam.UpdateMode, 1); this._status = 0; }
static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: params_cs filename"); return; } try { // Read model and verify that it is a MIP GRBEnv env = new GRBEnv(); GRBModel basemodel = new GRBModel(env, args[0]); if (basemodel.Get(GRB.IntAttr.IsMIP) == 0) { Console.WriteLine("The model is not an integer program"); Environment.Exit(1); } // Set a 5 second time limit basemodel.GetEnv().Set(GRB.DoubleParam.TimeLimit, 5); // Now solve the model with different values of MIPFocus double bestGap = GRB.INFINITY; GRBModel bestModel = null; for (int i = 0; i <= 3; ++i) { GRBModel m = new GRBModel(basemodel); m.GetEnv().Set(GRB.IntParam.MIPFocus, i); m.Optimize(); if (bestModel == null || bestGap > Gap(m)) { bestModel = m; bestGap = Gap(bestModel); } } // Finally, reset the time limit and continue to solve the // best model to optimality bestModel.GetEnv().Set(GRB.DoubleParam.TimeLimit, GRB.INFINITY); bestModel.Optimize(); Console.WriteLine("Solved with MIPFocus: " + bestModel.GetEnv().Get(GRB.IntParam.MIPFocus)); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public LinearModel(SolverType type, Action <string> logger, int threadCount = 0) { Type = type; _logger = logger; switch (type) { case SolverType.CPLEX: { CplexModel = new Cplex(); _cplexStatusCallback = new CplexStatusCallback(this) { }; CplexModel.SetOut(new CplexOutputHandler(logger)); CplexModel.Use(_cplexStatusCallback); if (threadCount > 0) { CplexModel.SetParam(Cplex.IntParam.Threads, threadCount); } } break; case SolverType.Gurobi: { GRBEnv gurobiEnvironment = new GRBEnv(); GurobiModel = new GRBModel(gurobiEnvironment); GurobiModel.GetEnv().Set(GRB.IntParam.UpdateMode, 1); // Enable immediate updates to better support the lazy initialization of the wrappers (at minor performance and memory costs) GurobiModel.GetEnv().Set(GRB.IntParam.OutputFlag, 0); if (threadCount > 0) { GurobiModel.GetEnv().Set(GRB.IntParam.Threads, threadCount); } _gurobiStatusCallback = new GurobiStatusCallback(this) { Logger = logger }; GurobiModel.SetCallback(_gurobiStatusCallback); } break; default: throw new ArgumentException("Unknown solver type: " + Type); } }
/// <summary> /// Sets a parameter to a given value by only specifying strings for both. /// </summary> /// <param name="paramName">The parameter to set.</param> /// <param name="paramValue">The value to set the parameter to.</param> public void SetParam(string paramName, string paramValue) { switch (Type) { case SolverType.CPLEX: { LogLine("Warning! Cannot set param by name for CPLEX - ignoring: " + paramName + "=" + paramValue); } break; case SolverType.Gurobi: { GurobiModel.GetEnv().Set(paramName, paramValue); LogLine(paramName + " set to (set by name): " + paramValue); } break; default: throw new ArgumentException("Unknown solver type: " + Type); } }
static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: lp_cs filename"); return; } try { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env, args[0]); model.Optimize(); int optimstatus = model.Get(GRB.IntAttr.Status); if (optimstatus == GRB.Status.INF_OR_UNBD) { model.GetEnv().Set(GRB.IntParam.Presolve, 0); model.Optimize(); optimstatus = model.Get(GRB.IntAttr.Status); } if (optimstatus == GRB.Status.OPTIMAL) { double objval = model.Get(GRB.DoubleAttr.ObjVal); Console.WriteLine("Optimal objective: " + objval); } else if (optimstatus == GRB.Status.INFEASIBLE) { Console.WriteLine("Model is infeasible"); // compute and write out IIS model.ComputeIIS(); model.Write("model.ilp"); } else if (optimstatus == GRB.Status.UNBOUNDED) { Console.WriteLine("Model is unbounded"); } else { Console.WriteLine("Optimization was stopped with status = " + optimstatus); } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public void Optimize(double timelimit = GRB.INFINITY, double mipGap = 0.00) { _model.GetEnv().Set(GRB.DoubleParam.TimeLimit, timelimit); _model.GetEnv().Set(GRB.DoubleParam.MIPGap, mipGap); _model.Optimize(); if (_model.Get(GRB.IntAttr.Status) == GRB.Status.INFEASIBLE) { _model.ComputeIIS(); Console.WriteLine("\nThe following constraints cannot be satisfied:"); foreach (GRBConstr c in _model.GetConstrs()) { if (c.Get(GRB.IntAttr.IISConstr) == 1) { Console.WriteLine(c.Get(GRB.StringAttr.ConstrName)); // Remove a single constraint from the model } } throw new Exception("Infeasible"); } }
static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: lpmethod_cs filename"); return; } try { // Read model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env, args[0]); GRBEnv menv = model.GetEnv(); // Solve the model with different values of Method int bestMethod = -1; double bestTime = menv.Get(GRB.DoubleParam.TimeLimit); for (int i = 0; i <= 2; ++i) { model.Reset(); menv.Set(GRB.IntParam.Method, i); model.Optimize(); if (model.Get(GRB.IntAttr.Status) == GRB.Status.OPTIMAL) { bestTime = model.Get(GRB.DoubleAttr.Runtime); bestMethod = i; // Reduce the TimeLimit parameter to save time // with other methods menv.Set(GRB.DoubleParam.TimeLimit, bestTime); } } // Report which method was fastest if (bestMethod == -1) { Console.WriteLine("Unable to solve this model"); } else { Console.WriteLine("Solved in " + bestTime + " seconds with Method: " + bestMethod); } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: tune_cs filename"); return; } try { GRBEnv env = new GRBEnv(); // Read model from file GRBModel model = new GRBModel(env, args[0]); // Set the TuneResults parameter to 1 model.GetEnv().Set(GRB.IntParam.TuneResults, 1); // Tune the model model.Tune(); // Get the number of tuning results int resultcount = model.Get(GRB.IntAttr.TuneResultCount); if (resultcount > 0) { // Load the tuned parameters into the model's environment model.GetTuneResult(0); // Write the tuned parameters to a file model.Write("tune.prm"); // Solve the model using the tuned parameters model.Optimize(); } // Dispose of model and environment model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: fixanddive_cs filename"); return; } try { // Read model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env, args[0]); // Collect integer variables and relax them List <GRBVar> intvars = new List <GRBVar>(); foreach (GRBVar v in model.GetVars()) { if (v.Get(GRB.CharAttr.VType) != GRB.CONTINUOUS) { intvars.Add(v); v.Set(GRB.CharAttr.VType, GRB.CONTINUOUS); } } model.GetEnv().Set(GRB.IntParam.OutputFlag, 0); model.Optimize(); // Perform multiple iterations. In each iteration, identify the first // quartile of integer variables that are closest to an integer value // in the relaxation, fix them to the nearest integer, and repeat. for (int iter = 0; iter < 1000; ++iter) { // create a list of fractional variables, sorted in order of // increasing distance from the relaxation solution to the nearest // integer value List <GRBVar> fractional = new List <GRBVar>(); foreach (GRBVar v in intvars) { double sol = Math.Abs(v.Get(GRB.DoubleAttr.X)); if (Math.Abs(sol - Math.Floor(sol + 0.5)) > 1e-5) { fractional.Add(v); } } Console.WriteLine("Iteration " + iter + ", obj " + model.Get(GRB.DoubleAttr.ObjVal) + ", fractional " + fractional.Count); if (fractional.Count == 0) { Console.WriteLine("Found feasible solution - objective " + model.Get(GRB.DoubleAttr.ObjVal)); break; } // Fix the first quartile to the nearest integer value fractional.Sort(new FractionalCompare()); int nfix = Math.Max(fractional.Count / 4, 1); for (int i = 0; i < nfix; ++i) { GRBVar v = fractional[i]; double fixval = Math.Floor(v.Get(GRB.DoubleAttr.X) + 0.5); v.Set(GRB.DoubleAttr.LB, fixval); v.Set(GRB.DoubleAttr.UB, fixval); Console.WriteLine(" Fix " + v.Get(GRB.StringAttr.VarName) + " to " + fixval + " ( rel " + v.Get(GRB.DoubleAttr.X) + " )"); } model.Optimize(); // Check optimization result if (model.Get(GRB.IntAttr.Status) != GRB.Status.OPTIMAL) { Console.WriteLine("Relaxation is infeasible"); break; } } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public static void Main(String[] args) { if (args.Length < 1) { Console.WriteLine("Usage: tsp_cs nnodes"); return; } int n = Convert.ToInt32(args[0]); try { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); // Must set LazyConstraints parameter when using lazy constraints model.GetEnv().Set(GRB.IntParam.LazyConstraints, 1); double[] x = new double[n]; double[] y = new double[n]; Random r = new Random(); for (int i = 0; i < n; i++) { x[i] = r.NextDouble(); y[i] = r.NextDouble(); } // Create variables GRBVar[,] vars = new GRBVar[n, n]; for (int i = 0; i < n; i++) { for (int j = 0; j <= i; j++) { vars[i, j] = model.AddVar(0.0, 1.0, distance(x, y, i, j), GRB.BINARY, "x" + i + "_" + j); vars[j, i] = vars[i, j]; } } // Integrate variables model.Update(); // Degree-2 constraints for (int i = 0; i < n; i++) { GRBLinExpr expr = 0; for (int j = 0; j < n; j++) { expr.AddTerm(1.0, vars[i, j]); } model.AddConstr(expr == 2.0, "deg2_" + i); } // Forbid edge from node back to itself for (int i = 0; i < n; i++) { vars[i, i].Set(GRB.DoubleAttr.UB, 0.0); } model.SetCallback(new tsp_cs(vars)); model.Optimize(); if (model.Get(GRB.IntAttr.SolCount) > 0) { int[] tour = findsubtour(model.Get(GRB.DoubleAttr.X, vars)); Console.Write("Tour: "); for (int i = 0; i < tour.Length; i++) { Console.Write(tour[i] + " "); } Console.WriteLine(); } // Dispose of model and environment model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); Console.WriteLine(e.StackTrace); } }
static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: mip2_cs filename"); return; } try { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env, args[0]); if (model.Get(GRB.IntAttr.IsMIP) == 0) { Console.WriteLine("Model is not a MIP"); return; } model.Optimize(); int optimstatus = model.Get(GRB.IntAttr.Status); double objval = 0; if (optimstatus == GRB.Status.OPTIMAL) { objval = model.Get(GRB.DoubleAttr.ObjVal); Console.WriteLine("Optimal objective: " + objval); } else if (optimstatus == GRB.Status.INF_OR_UNBD) { Console.WriteLine("Model is infeasible or unbounded"); return; } else if (optimstatus == GRB.Status.INFEASIBLE) { Console.WriteLine("Model is infeasible"); return; } else if (optimstatus == GRB.Status.UNBOUNDED) { Console.WriteLine("Model is unbounded"); return; } else { Console.WriteLine("Optimization was stopped with status = " + optimstatus); return; } /* Iterate over the solutions and compute the objectives */ GRBVar[] vars = model.GetVars(); model.GetEnv().Set(GRB.IntParam.OutputFlag, 0); Console.WriteLine(); for (int k = 0; k < model.Get(GRB.IntAttr.SolCount); ++k) { model.GetEnv().Set(GRB.IntParam.SolutionNumber, k); double objn = 0.0; for (int j = 0; j < vars.Length; j++) { objn += vars[j].Get(GRB.DoubleAttr.Obj) * vars[j].Get(GRB.DoubleAttr.Xn); } Console.WriteLine("Solution " + k + " has objective: " + objn); } Console.WriteLine(); model.GetEnv().Set(GRB.IntParam.OutputFlag, 1); /* Create a fixed model, turn off presolve and solve */ GRBModel fixedmodel = model.FixedModel(); fixedmodel.GetEnv().Set(GRB.IntParam.Presolve, 0); fixedmodel.Optimize(); int foptimstatus = fixedmodel.Get(GRB.IntAttr.Status); if (foptimstatus != GRB.Status.OPTIMAL) { Console.WriteLine("Error: fixed model isn't optimal"); return; } double fobjval = fixedmodel.Get(GRB.DoubleAttr.ObjVal); if (Math.Abs(fobjval - objval) > 1.0e-6 * (1.0 + Math.Abs(objval))) { Console.WriteLine("Error: objective values are different"); return; } GRBVar[] fvars = fixedmodel.GetVars(); double[] x = fixedmodel.Get(GRB.DoubleAttr.X, fvars); string[] vnames = fixedmodel.Get(GRB.StringAttr.VarName, fvars); for (int j = 0; j < fvars.Length; j++) { if (x[j] != 0.0) { Console.WriteLine(vnames[j] + " " + x[j]); } } // Dispose of models and env fixedmodel.Dispose(); model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public GurobiSolver4(Crossword crossword) { var wordLengthHistogram = new Dictionary <int, double>() { { 2, 0 }, { 3, 18 }, { 4, 24 }, { 5, 20 }, { 6, 18 }, { 7, 12 }, { 8, 4 }, { 9, 1 }, { 10, 1 }, { 11, 1 }, { 12, 1 }, { 13, 0 }, { 14, 0 }, { 15, 0 }, }; const int maxWordLength = 15; const int minWordLength = 2; int sizeY = crossword.Grid.GetLength(0); int sizeX = crossword.Grid.GetLength(1); var requiredAmountOfLetters = wordLengthHistogram.Sum(wl => wl.Key * wl.Value) / 1.8d; int totalFields = sizeX * sizeY; for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { totalFields -= crossword.Grid[y, x] is Blocked ? 1 : 0; } } int amountQuestions = (int)Math.Round(0.22 * totalFields); var wordLengthRatio = requiredAmountOfLetters / (totalFields - amountQuestions); GRBEnv env = new GRBEnv(); GRBModel m = new GRBModel(env); m.GetEnv().Method = 0; // 0 = letter, 1 = question GRBVar[,] fields = new GRBVar[sizeY, sizeX]; // 0 = right, 1 = down GRBVar[,] questionType = new GRBVar[sizeY, sizeX]; // 0 = Down, then right // 1 = Left, then down // 2 = Right, then down // 3 = Up, then right // Mostly null, except for places down and right of a blocked field or y==0 or x==0 GRBVar[,,] specialQuestionType = new GRBVar[sizeY, sizeX, 4]; var specialQuestionUsed = new GRBLinExpr[sizeY, sizeX]; for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { // create a var for every non-blocked field if (!(crossword.Grid[y, x] is Blocked)) { fields[y, x] = m.AddVar(0, 1, 0, GRB.BINARY, "Field" + y + "_" + x); questionType[y, x] = m.AddVar(0, 1, 0, GRB.BINARY, "QType" + y + "_" + x); // Is null except for places down and right of a blocked field or y==0 or x==0 if (y == 0 || x == 0 || crossword.Grid[y - 1, x] is Blocked || crossword.Grid[y, x - 1] is Blocked) { for (int t = 0; t < 4; t++) { specialQuestionType[y, x, t] = m.AddVar(0, 1, 0, GRB.BINARY, "SpecialQType" + t + "_" + y + "_" + x); } specialQuestionUsed[y, x] = specialQuestionType[y, x, 0] + specialQuestionType[y, x, 1] + specialQuestionType[y, x, 2] + specialQuestionType[y, x, 3]; // Max 1 special type, can also be no special question m.AddConstr(specialQuestionUsed[y, x] <= 1, "MaxOneSpecialQuestion" + y + "_" + x); } } } } // TEST //m.AddConstr(specialQuestionType[0, 0, 0] == 1); GRBLinExpr allFieldsSum = new GRBLinExpr(); for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { if (crossword.Grid[y, x] is Blocked) { continue; } allFieldsSum += fields[y, x]; bool noQuestionToTheRightAllowed = false; bool noQuestionTowardsDownAllowed = false; if (x + minWordLength < sizeX && !crossword.HasBlock(y, x, y, x + minWordLength)) { // for right: if [0,0] is question, [0,1..3] must not be question var totalQuestionsHorizontal = fields.SumRange(y, x + 1, y, x + minWordLength); var isQuestionAndPointsRight = fields[y, x] + (1 - questionType[y, x]) - 1; if ((object)specialQuestionUsed[y, x] != null) { isQuestionAndPointsRight += (1 - specialQuestionUsed[y, x]) - 1; } for (int len = 1; len <= minWordLength; len++) { m.AddConstr(isQuestionAndPointsRight <= 1 - fields[y, x + len], "MinWordLength3" + y + "_" + x + "_right" + len); } } else { noQuestionToTheRightAllowed = true; } // for down: if (y + minWordLength < sizeY && !crossword.HasBlock(y, x, y + minWordLength, x)) { var totalQuestionsVertical = fields.SumRange(y + 1, x, y + minWordLength, x); var isQuestionAndPointsDown = fields[y, x] + questionType[y, x] - 1; if ((object)specialQuestionUsed[y, x] != null) { isQuestionAndPointsDown += (1 - specialQuestionUsed[y, x]) - 1; } for (int len = 1; len <= minWordLength; len++) { m.AddConstr(isQuestionAndPointsDown <= 1 - fields[y + len, x], "MinWordLength3" + y + "_" + x + "_down" + len); } } else { noQuestionTowardsDownAllowed = true; } bool atLeastOneSpecialAllowed = false; if ((object)specialQuestionUsed[y, x] != null) { // down, then right if (y + 1 < sizeY && x + minWordLength - 1 < sizeX && !crossword.HasBlock(y + 1, x, y + 1, x + minWordLength - 1)) { for (int len = 1; len <= minWordLength; len++) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= 1 - fields[y + 1, x + len - 1], "MinWordLength3" + y + "_" + x + "_downRight" + len); } if (x > 0) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y + 1, x - 1], "QuestionBeforeSQ" + y + "_" + x + "_downRight"); } atLeastOneSpecialAllowed = true; } else { m.AddConstr(specialQuestionType[y, x, 0] == 0, "NoSpecialQuestionAllowed" + y + "_" + x + "_downRight"); } // left, then down if (y + minWordLength - 1 < sizeY && x - 1 >= 0 && !crossword.HasBlock(y, x - 1, y + minWordLength - 1, x - 1)) { for (int len = 1; len <= minWordLength; len++) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 1] - 1 <= 1 - fields[y + len - 1, x - 1], "MinWordLength3" + y + "_" + x + "_leftDown" + len); } if (y > 0) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 1] - 1 <= fields[y - 1, x - 1], "QuestionBeforeSQ" + y + "_" + x + "_leftDown"); } atLeastOneSpecialAllowed = true; } else { m.AddConstr(specialQuestionType[y, x, 1] == 0, "NoSpecialQuestionAllowed" + y + "_" + x + "_leftDown"); } // right, then down if (y + minWordLength - 1 < sizeY && x + 1 < sizeX && !crossword.HasBlock(y, x + 1, y + minWordLength - 1, x + 1)) { for (int len = 1; len <= minWordLength; len++) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 2] - 1 <= 1 - fields[y + len - 1, x + 1], "MinWordLength3" + y + "_" + x + "_rightDown" + len); } if (y > 0) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 2] - 1 <= fields[y - 1, x + 1], "QuestionBeforeSQ" + y + "_" + x + "_rightDown"); } atLeastOneSpecialAllowed = true; } else { m.AddConstr(specialQuestionType[y, x, 2] == 0, "NoSpecialQuestionAllowed" + y + "_" + x + "_rightDown"); } // up, then right if (y - 1 >= 0 && x + minWordLength - 1 < sizeX && !crossword.HasBlock(y - 1, x, y - 1, x + minWordLength - 1)) { for (int len = 1; len <= minWordLength; len++) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 3] - 1 <= 1 - fields[y - 1, x + len - 1], "MinWordLength3" + y + "_" + x + "_upRight" + len); } if (x > 0) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 3] - 1 <= fields[y - 1, x - 1], "QuestionBeforeSQ" + y + "_" + x + "_upRight"); } atLeastOneSpecialAllowed = true; } else { m.AddConstr(specialQuestionType[y, x, 3] == 0, "NoSpecialQuestionAllowed" + y + "_" + x + "_upRight"); } if (!atLeastOneSpecialAllowed) { m.AddConstr(specialQuestionUsed[y, x] == 0, "NoSpecialQuestionAllowedAtALl" + y + "_" + x); } } if (noQuestionToTheRightAllowed && noQuestionTowardsDownAllowed) { if (!atLeastOneSpecialAllowed) { m.AddConstr(fields[y, x] == 0, "NoQuestionAllowed" + y + "_" + x); } else { m.AddConstr(specialQuestionUsed[y, x] == 1, "OnlySpecialQuestionAllowed" + y + "_" + x); } } else { if (noQuestionToTheRightAllowed) { m.AddConstr(questionType[y, x] == 1, "QuestionCantPointRight" + y + "_" + x); } if (noQuestionTowardsDownAllowed) { m.AddConstr(questionType[y, x] == 0, "QuestionCantPointDown" + y + "_" + x); } } // max word length constraints // for right: if [0,0] is question, [0,1..maxLength+1] must have at least another question field if (x + maxWordLength + 1 < sizeX && !crossword.HasBlock(y, x, y, x + maxWordLength + 1)) { var allHorizontalFields = new GRBLinExpr(); for (int xi = 1; xi <= maxWordLength + 1; xi++) { allHorizontalFields += fields[y, x + xi]; } if ((object)specialQuestionUsed[y, x] != null) { m.AddConstr(fields[y, x] + (1 - questionType[y, x]) + (1 - specialQuestionUsed[y, x]) - 2 <= allHorizontalFields, "MaxLengthHorizontal" + y + "_" + x); } else { m.AddConstr(fields[y, x] + (1 - questionType[y, x]) - 1 <= allHorizontalFields, "MaxLengthHorizontal" + y + "_" + x); } } // for down: if (y + maxWordLength + 1 < sizeY && !crossword.HasBlock(y, x, y + maxWordLength + 1, x)) { var fieldsSum = fields.SumRange(y + 1, x, y + maxWordLength + 1, x); if ((object)specialQuestionUsed[y, x] != null) { m.AddConstr(fields[y, x] + questionType[y, x] + (1 - specialQuestionUsed[y, x]) - 2 <= fieldsSum, "MaxLengthVertical" + y + "_" + x); } else { m.AddConstr(fields[y, x] + questionType[y, x] - 1 <= fieldsSum, "MaxLengthVertical" + y + "_" + x); } } if ((object)specialQuestionUsed[y, x] != null) { // down, then right if (y + 1 < sizeY && x + maxWordLength < sizeX && !crossword.HasBlock(y + 1, x, y + 1, x + maxWordLength)) { var fieldsSum = fields.SumRange(y + 1, x, y + 1, x + maxWordLength); m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fieldsSum, "MaxLengthSpecialQuestion0_" + y + "_" + x); // if there is a normal field to the left of the word, it has to be a question if (x - 1 >= 0 && !crossword.HasBlock(y + 1, x - 1)) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y + 1, x - 1], "QuestionRequiredBeforeSpecialQuestion0Word_" + y + "_" + x); } } // left, then down if (y + maxWordLength < sizeY && x - 1 >= 0 && !crossword.HasBlock(y, x - 1, y + maxWordLength, x - 1)) { var fieldsSum = fields.SumRange(y, x - 1, y + maxWordLength, x - 1); m.AddConstr(fields[y, x] + specialQuestionType[y, x, 1] - 1 <= fieldsSum, "MaxLengthSpecialQuestion1_" + y + "_" + x); if (y - 1 >= 0 && !crossword.HasBlock(y - 1, x - 1)) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y - 1, x - 1], "QuestionRequiredBeforeSpecialQuestion1Word_" + y + "_" + x); } } // right, then down if (y + maxWordLength < sizeY && x + 1 < sizeX && !crossword.HasBlock(y, x + 1, y + maxWordLength, x + 1)) { var fieldsSum = fields.SumRange(y, x + 1, y + maxWordLength, x + 1); m.AddConstr(fields[y, x] + specialQuestionType[y, x, 2] - 1 <= fieldsSum, "MaxLengthSpecialQuestion2_" + y + "_" + x); if (y - 1 >= 0 && !crossword.HasBlock(y - 1, x + 1)) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y - 1, x + 1], "QuestionRequiredBeforeSpecialQuestion2Word_" + y + "_" + x); } } // up, then right if (y - 1 >= 0 && x + maxWordLength < sizeX && !crossword.HasBlock(y - 1, x, y - 1, x + maxWordLength)) { var fieldsSum = fields.SumRange(y - 1, x, y - 1, x + maxWordLength); m.AddConstr(fields[y, x] + specialQuestionType[y, x, 3] - 1 <= fieldsSum, "MaxLengthSpecialQuestion3_" + y + "_" + x); if (x - 1 >= 0 && !crossword.HasBlock(y - 1, x - 1)) { m.AddConstr(fields[y, x] + specialQuestionType[y, x, 0] - 1 <= fields[y - 1, x - 1], "QuestionRequiredBeforeSpecialQuestion3Word_" + y + "_" + x); } } } } } // Does a field belong to zero, one or two questions? var partOfAWord = new GRBLinExpr[sizeY, sizeX, 6]; for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { // this constraint doesn't work for [0,0] if (crossword.HasBlock(y, x)) { continue; } // Is this field attached to a question on the left, pointing right? var attachedToHorizontalQuestion = m.AddVar(0, 1, 0, GRB.BINARY, "attachedToHorizontalQuestion" + y + "_" + x); for (int len = 1; len <= maxWordLength; len++) { if (x - len < 0 || crossword.HasBlock(y, x - len, y, x)) { continue; } var isQuestionAndPointsRight = fields[y, x - len] + (1 - questionType[y, x - len]); if ((object)specialQuestionUsed[y, x - len] != null) { isQuestionAndPointsRight += (1 - specialQuestionUsed[y, x - len]) - 1; } var questionsInbetween = fields.SumRange(y, x - len + 1, y, x); m.AddConstr(attachedToHorizontalQuestion >= isQuestionAndPointsRight - 1 - questionsInbetween, "attachedToHorizontalQuestionConstraint0_" + y + "_" + x); // 0 IF first question is not pointing right OR there is no question to the left // firstQuestion ==> total fields < 2 if ((object)specialQuestionUsed[y, x - len] != null) { m.AddConstr(attachedToHorizontalQuestion <= questionsInbetween + (1 - fields[y, x - len]) + 1 - (questionType[y, x - len] + specialQuestionUsed[y, x - len]) * 0.5, "attachedToHorizontalQuestionConstraint1_" + y + "_" + x); // the first question but DOESNT look right } else { m.AddConstr(attachedToHorizontalQuestion <= questionsInbetween + (1 - fields[y, x - len]) + 1 - questionType[y, x - len], "attachedToHorizontalQuestionConstraint2_" + y + "_" + x); // the first question but DOESNT look right } } var questionsToTheLeft = new GRBLinExpr(); int qlCount = 0; for (int len = 0; len <= maxWordLength; len++) { if (x - len < 0 || crossword.HasBlock(y, x - len, y, x)) { continue; } questionsToTheLeft += fields[y, x - len]; qlCount++; } if (qlCount > 0) { m.AddConstr(attachedToHorizontalQuestion <= questionsToTheLeft, "attachedToHorizontalQuestionConstraint4_" + y + "_" + x); } // Is this field attached to a question pointing towards down? var attachedToVerticalQuestion = m.AddVar(0, 1, 0, GRB.BINARY, "attachedToVerticalQuestion" + y + "_" + x); for (int len = 1; len <= maxWordLength; len++) { if (y - len < 0 || crossword.HasBlock(y - len, x, y, x)) { continue; } var isQuestionAndPointsDown = fields[y - len, x] + questionType[y - len, x]; if ((object)specialQuestionUsed[y - len, x] != null) { isQuestionAndPointsDown += (1 - specialQuestionUsed[y - len, x]) - 1; } var questionsInbetween = fields.SumRange(y - len + 1, x, y, x); m.AddConstr(attachedToVerticalQuestion >= isQuestionAndPointsDown - 1 - questionsInbetween, "attachedToVerticalQuestionConstraint0_" + y + "_" + x); if ((object)specialQuestionUsed[y - len, x] != null) { m.AddConstr(attachedToVerticalQuestion <= questionsInbetween + (1 - fields[y - len, x]) + 1 - (1 - questionType[y - len, x] + specialQuestionUsed[y - len, x]) * 0.5, "attachedToVerticalQuestionConstraint1_" + y + "_" + x); // the first question but DOESNT look down OR IS specialquestion } else { m.AddConstr(attachedToVerticalQuestion <= questionsInbetween + (1 - fields[y - len, x]) + 1 - (1 - questionType[y - len, x]), "attachedToVerticalQuestionConstraint2_" + y + "_" + x); // the first question but DOESNT look down OR IS specialquestion } } var questionsTowardsDown = new GRBLinExpr(); int qdCount = 0; for (int len = 0; len <= maxWordLength; len++) { if (y - len < 0 || crossword.HasBlock(y - len, x, y, x)) { continue; } questionsTowardsDown += fields[y - len, x]; qdCount++; } if (qdCount > 0) { m.AddConstr(attachedToVerticalQuestion <= questionsTowardsDown, "attachedToVerticalQuestionConstraint3_" + y + "_" + x); } var attachedToSpecialQuestions = new GRBLinExpr[4]; var spAll = new GRBLinExpr(); for (int type = 0; type < 4; type++) { attachedToSpecialQuestions[type] = AttachedToSpecialQuestion(y, x, type, crossword, m, sizeX, sizeY, maxWordLength, fields, specialQuestionUsed, specialQuestionType); if ((object)attachedToSpecialQuestions[type] != null) { spAll += attachedToSpecialQuestions[type]; } } // if attached to horizontal question, can't be attached to horizontal sq (0, 3) if ((object)attachedToSpecialQuestions[0] != null) { m.AddConstr((1 - attachedToHorizontalQuestion) >= attachedToSpecialQuestions[0], "noHorizontalOverlap1_" + y + "_" + x); } if ((object)attachedToSpecialQuestions[3] != null) { m.AddConstr((1 - attachedToHorizontalQuestion) >= attachedToSpecialQuestions[3], "noHorizontalOverlap2_" + y + "_" + x); } // give preference to one horizontal kind of sq if ((object)attachedToSpecialQuestions[0] != null && (object)attachedToSpecialQuestions[3] != null) { m.AddConstr((1 - attachedToSpecialQuestions[0]) >= attachedToSpecialQuestions[3], "noHorizontalOverlap3_" + y + "_" + x); } // if attached to vertical question, can't be attached to vertical sq (1, 2) if ((object)attachedToSpecialQuestions[1] != null) { m.AddConstr((1 - attachedToVerticalQuestion) >= attachedToSpecialQuestions[1], "noVerticalOverlap1_" + y + "_" + x); } if ((object)attachedToSpecialQuestions[2] != null) { m.AddConstr((1 - attachedToVerticalQuestion) >= attachedToSpecialQuestions[2], "noVerticalOverlap2_" + y + "_" + x); } // give preference to one horizontal kind of sq if ((object)attachedToSpecialQuestions[1] != null && (object)attachedToSpecialQuestions[2] != null) { m.AddConstr((1 - attachedToSpecialQuestions[1]) >= attachedToSpecialQuestions[2], "noVerticalOverlap3_" + y + "_" + x); } var c = m.AddConstr(attachedToHorizontalQuestion + attachedToVerticalQuestion + spAll >= 1 - fields[y, x], "AttachedToQuestionConstraint_" + y + "_" + x); //c.Lazy = 1; partOfAWord[y, x, 0] = attachedToHorizontalQuestion; partOfAWord[y, x, 1] = attachedToVerticalQuestion; partOfAWord[y, x, 2] = attachedToSpecialQuestions[0]; partOfAWord[y, x, 3] = attachedToSpecialQuestions[1]; partOfAWord[y, x, 4] = attachedToSpecialQuestions[2]; partOfAWord[y, x, 5] = attachedToSpecialQuestions[3]; } } // right now, [0,0] can only be a question //if (!crossword.HasBlock(0, 0)) m.AddConstr(fields[0, 0] == 1); // and similarly the bottom 3x3 can only be letters for (int y = sizeY - minWordLength; y < sizeY; y++) { for (int x = sizeX - minWordLength; x < sizeX; x++) { if (!crossword.HasBlock(y, x)) { m.AddConstr(fields[y, x] == 0, "BottomOnlyLetters_" + y + "_" + x); } } } // Objective: // questions should be around ~22% (allFieldsSum ~= amountQuestions) /*int tolerance = (int)(amountQuestions * 0.1); * m.AddConstr(allFieldsSum >= amountQuestions - tolerance, "amountOfQuestionsTolerance_1"); * m.AddConstr(allFieldsSum <= amountQuestions + tolerance, "amountOfQuestionsTolerance_2");*/ m.AddConstr(allFieldsSum == amountQuestions); // uncrossed var partOfWordTotals = new GRBLinExpr[sizeY, sizeX]; for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { if (!crossword.HasBlock(y, x)) //(x >= 1 || y >= 1) && { var partOfWordTotal = new GRBLinExpr(); for (int t = 0; t < 6; t++) { if ((object)partOfAWord[y, x, t] != null) { partOfWordTotal += partOfAWord[y, x, t]; } } partOfWordTotals[y, x] = partOfWordTotal; } } } for (int y = 0; y < sizeY - 1; y++) { for (int x = 0; x < sizeX - 1; x++) { if (!crossword.HasBlock(y, x)) //(x >= 1 || y >= 1) && { if (!crossword.HasBlock(y + 1, x)) { m.AddConstr(partOfWordTotals[y, x] + partOfWordTotals[y + 1, x] >= (1 - fields[y, x] - fields[y + 1, x]) * 3, "noUncrossedFields" + y + "_" + x); } if (!crossword.HasBlock(y, x + 1)) { m.AddConstr(partOfWordTotals[y, x] + partOfWordTotals[y, x + 1] >= (1 - fields[y, x] - fields[y, x + 1]) * 3, "noUncrossedFields" + y + "_" + x); } } } } // penalty for nearby uncrossed letters (dead fields) /*var deadFieldPenalty = new GRBLinExpr(); * for (int y = 0; y < sizeY; y++) * { * for (int x = 0; x < sizeX; x++) * { * var hby = y - 1 >= 0 && !crossword.HasBlock(y - 1, x); * var hbx = x - 1 >= 0 && !crossword.HasBlock(y, x - 1); * if (!crossword.HasBlock(y, x) && (hby || hbx)) * { * var isDeadArea = m.AddVar(0, 1, 0, GRB.BINARY, "isDeadArea" + y + "_" + x); * if (hby) m.AddConstr(isDeadArea >= uncrossedLetters[y, x] + uncrossedLetters[y - 1, x] - 1, "deadAreaConstr1" + y + "_" + x); * if (hbx) m.AddConstr(isDeadArea >= uncrossedLetters[y, x] + uncrossedLetters[y, x - 1] - 1, "deadAreaConstr2" + y + "_" + x); * m.AddConstr(isDeadArea <= uncrossedLetters[y, x]); * if (hby && hbx) * m.AddConstr(isDeadArea <= uncrossedLetters[y - 1, x] + uncrossedLetters[y, x - 1], "deadAreaConstr3" + y + "_" + x); * else if (hby) * m.AddConstr(isDeadArea <= uncrossedLetters[y - 1, x], "deadAreaConstr4" + y + "_" + x); * else if (hbx) * m.AddConstr(isDeadArea <= uncrossedLetters[y, x - 1], "deadAreaConstr5" + y + "_" + x); * deadFieldPenalty += isDeadArea; * } * } * }*/ // ideal histogram comparison //var wordHistogramDifferences = new GRBLinExpr(); var wlTotals = new Dictionary <int, GRBLinExpr>(); foreach (var wl in wordLengthHistogram.Keys) { var total = new GRBLinExpr(); for (int y = 0; y + wl - 1 < sizeY; y++) { for (int x = 0; x < sizeX; x++) { if (crossword.HasBlock(y, x, y + wl - 1, x)) { continue; } // true if field-1 is question or start AND field + wl (after word) is question or end var hasLength = m.AddVar(0, 1, 0, GRB.BINARY, "hasLenVert" + wl + "__" + y + "_" + x); var sum = fields.SumRange(y, x, y + wl - 1, x); // no questions inbetween for (int i = 0; i < wl; i++) { m.AddConstr(hasLength <= 1 - fields[y + i, x]); } // question at end if (y + wl < sizeY && !crossword.HasBlock(y + wl, x)) { sum += (1 - fields[y + wl, x]); m.AddConstr(hasLength <= fields[y + wl, x]); } // question at start if (y - 1 >= 0 && !crossword.HasBlock(y - 1, x)) { sum += (1 - fields[y - 1, x]); m.AddConstr(hasLength <= fields[y - 1, x]); } // counts if a letter is attached to a horizontal question var qsum = new GRBLinExpr(); if ((object)partOfAWord[y, x, 1] != null) { qsum += partOfAWord[y, x, 1]; } if ((object)partOfAWord[y, x, 3] != null) { qsum += partOfAWord[y, x, 3]; } if ((object)partOfAWord[y, x, 4] != null) { qsum += partOfAWord[y, x, 4]; } sum += 1 - qsum; m.AddConstr(hasLength <= qsum); m.AddConstr(hasLength >= 1 - sum); total += hasLength; } } for (int y = 0; y < sizeY; y++) { for (int x = 0; x + wl - 1 < sizeX; x++) { if (crossword.HasBlock(y, x, y, x + wl - 1)) { continue; } var hasLength = m.AddVar(0, 1, 0, GRB.BINARY, "hasLenHoriz" + wl + "__" + y + "_" + x); var sum = fields.SumRange(y, x, y, x + wl - 1); // no questions inbetween for (int i = 0; i < wl; i++) { m.AddConstr(hasLength <= 1 - fields[y, x + i]); } // question at end if (x + wl < sizeX && !crossword.HasBlock(y, x + wl)) { sum += (1 - fields[y, x + wl]); m.AddConstr(hasLength <= fields[y, x + wl]); } // question at start if (x - 1 >= 0 && !crossword.HasBlock(y, x - 1)) { sum += (1 - fields[y, x - 1]); m.AddConstr(hasLength <= fields[y, x - 1]); } // counts if a letter is attached to a horizontal question var qsum = new GRBLinExpr(); if ((object)partOfAWord[y, x, 0] != null) { qsum += partOfAWord[y, x, 0]; } if ((object)partOfAWord[y, x, 2] != null) { qsum += partOfAWord[y, x, 2]; } if ((object)partOfAWord[y, x, 5] != null) { qsum += partOfAWord[y, x, 5]; } sum += 1 - qsum; m.AddConstr(hasLength <= qsum); m.AddConstr(hasLength >= 1 - sum); total += hasLength; } } if (wl <= 9) { wlTotals.Add(wl, total); } else { wlTotals[9] += total; } } var wlPenalty = new GRBLinExpr(); var wordCounts = m.AddVars(8, 0, amountQuestions * 2, GRB.INTEGER, "amount"); foreach (var wl in wlTotals.Keys) { var input = wordCounts[wl - 2]; m.AddConstr(input == wlTotals[wl]); var absRes = m.AddVar(0, 100, 0, GRB.CONTINUOUS, "absRes"); Console.WriteLine(wl == 9 ? 4 : wordLengthHistogram[wl]); var percentageDiff = input * (100d / amountQuestions) - (wl == 9 ? 4 : wordLengthHistogram[wl]); m.AddConstr(percentageDiff <= absRes, "absPos"); m.AddConstr(-percentageDiff <= absRes, "absNeg"); wlPenalty += absRes; } wlPenalty *= (1d / 8); // question field clusters // in a field of 2x2, minimize the nr of fields where there are 2-4 questions resp. maximize 0-1 questions //var clusterPenalty = new GRBLinExpr(); int area = 3; for (int y = 0; y < sizeY - (area - 1); y++) { for (int x = 0; x < sizeX - (area - 1); x++) { var clusterTotal = new GRBLinExpr(); int ct = 0; for (int i = 0; i < area; i++) { for (int j = 0; j < area; j++) { if (crossword.HasBlock(y + i, x + j) || (i == 1 && j == 1)) { continue; } clusterTotal += fields[y + i, x + j]; ct++; } } if (ct >= 2 && !crossword.HasBlock(y + 1, x + 1)) { //var varClusterTotalPenalty = m.AddVar(0, 1, 0, GRB.BINARY, "varClusterTotalPenalty" + y + "_" + x); // 0-1 = good, 2-4 = bad m.AddConstr(clusterTotal - 1 <= (1 - fields[y + 1, x + 1]) * 8, "cluster" + y + "_" + x); /*m.AddConstr(varClusterTotalPenalty <= clusterTotal * 0.5, "clusterPenaltyConstr1_" + y + "_" + x); * m.AddConstr(varClusterTotalPenalty >= (clusterTotal - 1) * (1d / 3), "clusterPenaltyConstr2_" + y + "_" + x); * clusterPenalty += varClusterTotalPenalty;*/ } } } //m.AddConstr(deadFieldPenalty <= 30); //amountOfQuestionsRating * (100d / sizeX / sizeY) + manyCrossedWords + + wordHistogramDifferences // clusterPenalty * 100 m.SetObjective(wlPenalty, GRB.MINIMIZE); m.SetCallback(new GRBMipSolCallback(crossword, fields, questionType, specialQuestionType, true, wordCounts)); // Insert previous solution /*var cwdCheck = new Crossword(@"C:\Users\Roman Bolzern\Documents\GitHub\Crossword\docs\15x15_1_noDoubles.cwg"); * cwdCheck.Draw(); * for (int y = 0; y < cwdCheck.Grid.GetLength(0); y++) * { * for (int x = 0; x < cwdCheck.Grid.GetLength(1); x++) * { * if (cwdCheck.Grid[y, x] is Question) * { * m.AddConstr(fields[y, x] == 1); * var q = (Question)cwdCheck.Grid[y, x]; * if (q.Arrow == Question.ArrowType.Right) * { * m.AddConstr(questionType[y, x] == 0); * if ((object)specialQuestionType[y, x, 0] != null) * m.AddConstr(specialQuestionType[y, x, 0] + specialQuestionType[y, x, 1] + specialQuestionType[y, x, 2] + specialQuestionType[y, x, 3] == 0); * } * else if (q.Arrow == Question.ArrowType.Down) * { * m.AddConstr(questionType[y, x] == 1); * if ((object)specialQuestionType[y, x, 0] != null) * m.AddConstr(specialQuestionType[y, x, 0] + specialQuestionType[y, x, 1] + specialQuestionType[y, x, 2] + specialQuestionType[y, x, 3] == 0); * } * else if (q.Arrow == Question.ArrowType.DownRight) * { * m.AddConstr(specialQuestionType[y, x, 0] == 1); * } * else if (q.Arrow == Question.ArrowType.LeftDown) * { * m.AddConstr(specialQuestionType[y, x, 1] == 1); * } * else if (q.Arrow == Question.ArrowType.RightDown) * { * m.AddConstr(specialQuestionType[y, x, 2] == 1); * } * else if (q.Arrow == Question.ArrowType.UpRight) * { * m.AddConstr(specialQuestionType[y, x, 3] == 1); * } * } * else if (cwdCheck.Grid[y, x] is Letter) * { * m.AddConstr(fields[y, x] == 0); * } * } * }*/ m.Optimize(); m.ComputeIIS(); m.Write("model.ilp"); m.Dispose(); env.Dispose(); }
public static void Main(String[] args) { if (args.Length < 1) { Console.WriteLine("Usage: tsp_cs nnodes"); return; } int n = Convert.ToInt32(args[0]); try { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); // Must disable dual reductions when using lazy constraints model.GetEnv().Set(GRB.IntParam.DualReductions, 0); double[] x = new double[n]; double[] y = new double[n]; Random r = new Random(); for (int i = 0; i < n; i++) { x[i] = r.NextDouble(); y[i] = r.NextDouble(); } // Create variables GRBVar[,] vars = new GRBVar[n, n]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) vars[i, j] = model.AddVar(0.0, 1.0, distance(x, y, i, j), GRB.BINARY, "x"+i+"_"+j); // Integrate variables model.Update(); // Degree-2 constraints for (int i = 0; i < n; i++) { GRBLinExpr expr = 0; for (int j = 0; j < n; j++) expr += vars[i, j]; model.AddConstr(expr == 2.0, "deg2_"+i); } // Forbid edge from node back to itself for (int i = 0; i < n; i++) vars[i, i].Set(GRB.DoubleAttr.UB, 0.0); // Symmetric TSP for (int i = 0; i < n; i++) for (int j = 0; j < i; j++) model.AddConstr(vars[i, j]== vars[j, i], ""); model.SetCallback(new tsp_cs(vars)); model.Optimize(); if (model.Get(GRB.IntAttr.SolCount) > 0) { int[] tour = findsubtour(model.Get(GRB.DoubleAttr.X, vars)); Console.Write("Tour: "); for (int i = 0; i < tour.Length; i++) Console.Write(tour[i] + " "); Console.WriteLine(); } // Dispose of model and environment model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); Console.WriteLine(e.StackTrace); } }
static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: mip2_cs filename"); return; } try { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env, args[0]); if (model.Get(GRB.IntAttr.IsMIP) == 0) { Console.WriteLine("Model is not a MIP"); return; } model.Optimize(); int optimstatus = model.Get(GRB.IntAttr.Status); double objval = 0; if (optimstatus == GRB.Status.OPTIMAL) { objval = model.Get(GRB.DoubleAttr.ObjVal); Console.WriteLine("Optimal objective: " + objval); } else if (optimstatus == GRB.Status.INF_OR_UNBD) { Console.WriteLine("Model is infeasible or unbounded"); return; } else if (optimstatus == GRB.Status.INFEASIBLE) { Console.WriteLine("Model is infeasible"); return; } else if (optimstatus == GRB.Status.UNBOUNDED) { Console.WriteLine("Model is unbounded"); return; } else { Console.WriteLine("Optimization was stopped with status = " + optimstatus); return; } /* Iterate over the solutions and compute the objectives */ GRBVar[] vars = model.GetVars(); model.GetEnv().Set(GRB.IntParam.OutputFlag, 0); Console.WriteLine(); for (int k = 0; k < model.Get(GRB.IntAttr.SolCount); ++k) { model.GetEnv().Set(GRB.IntParam.SolutionNumber, k); double objn = 0.0; for (int j = 0; j < vars.Length; j++) { objn += vars[j].Get(GRB.DoubleAttr.Obj) * vars[j].Get(GRB.DoubleAttr.Xn); } Console.WriteLine("Solution " + k + " has objective: " + objn); } Console.WriteLine(); model.GetEnv().Set(GRB.IntParam.OutputFlag, 1); /* Create a fixed model, turn off presolve and solve */ GRBModel fixedmodel = model.FixedModel(); fixedmodel.GetEnv().Set(GRB.IntParam.Presolve, 0); fixedmodel.Optimize(); int foptimstatus = fixedmodel.Get(GRB.IntAttr.Status); if (foptimstatus != GRB.Status.OPTIMAL) { Console.WriteLine("Error: fixed model isn't optimal"); return; } double fobjval = fixedmodel.Get(GRB.DoubleAttr.ObjVal); if (Math.Abs(fobjval - objval) > 1.0e-6 * (1.0 + Math.Abs(objval))) { Console.WriteLine("Error: objective values are different"); return; } GRBVar[] fvars = fixedmodel.GetVars(); double[] x = fixedmodel.Get(GRB.DoubleAttr.X, fvars); string[] vnames = fixedmodel.Get(GRB.StringAttr.VarName, fvars); for (int j = 0; j < fvars.Length; j++) { if (x[j] != 0.0) Console.WriteLine(vnames[j] + " " + x[j]); } // Dispose of models and env fixedmodel.Dispose(); model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { // Warehouse demand in thousands of units double[] Demand = new double[] { 15, 18, 14, 20 }; // Plant capacity in thousands of units double[] Capacity = new double[] { 20, 22, 17, 19, 18 }; // Fixed costs for each plant double[] FixedCosts = new double[] { 12000, 15000, 17000, 13000, 16000 }; // Transportation costs per thousand units double[,] TransCosts = new double[, ] { { 4000, 2000, 3000, 2500, 4500 }, { 2500, 2600, 3400, 3000, 4000 }, { 1200, 1800, 2600, 4100, 3000 }, { 2200, 2600, 3100, 3700, 3200 } }; // Number of plants and warehouses int nPlants = Capacity.Length; int nWarehouses = Demand.Length; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.Set(GRB.StringAttr.ModelName, "facility"); // Plant open decision variables: open[p] == 1 if plant p is open. GRBVar[] open = new GRBVar[nPlants]; for (int p = 0; p < nPlants; ++p) { open[p] = model.AddVar(0, 1, FixedCosts[p], GRB.BINARY, "Open" + p); } // Transportation decision variables: how much to transport from // a plant p to a warehouse w GRBVar[,] transport = new GRBVar[nWarehouses, nPlants]; for (int w = 0; w < nWarehouses; ++w) { for (int p = 0; p < nPlants; ++p) { transport[w, p] = model.AddVar(0, GRB.INFINITY, TransCosts[w, p], GRB.CONTINUOUS, "Trans" + p + "." + w); } } // The objective is to minimize the total fixed and variable costs model.Set(GRB.IntAttr.ModelSense, 1); // Update model to integrate new variables model.Update(); // Production constraints // Note that the right-hand limit sets the production to zero if // the plant is closed for (int p = 0; p < nPlants; ++p) { GRBLinExpr ptot = 0.0; for (int w = 0; w < nWarehouses; ++w) { ptot.AddTerm(1.0, transport[w, p]); } model.AddConstr(ptot <= Capacity[p] * open[p], "Capacity" + p); } // Demand constraints for (int w = 0; w < nWarehouses; ++w) { GRBLinExpr dtot = 0.0; for (int p = 0; p < nPlants; ++p) { dtot.AddTerm(1.0, transport[w, p]); } model.AddConstr(dtot == Demand[w], "Demand" + w); } // Guess at the starting point: close the plant with the highest // fixed costs; open all others // First, open all plants for (int p = 0; p < nPlants; ++p) { open[p].Set(GRB.DoubleAttr.Start, 1.0); } // Now close the plant with the highest fixed cost Console.WriteLine("Initial guess:"); double maxFixed = -GRB.INFINITY; for (int p = 0; p < nPlants; ++p) { if (FixedCosts[p] > maxFixed) { maxFixed = FixedCosts[p]; } } for (int p = 0; p < nPlants; ++p) { if (FixedCosts[p] == maxFixed) { open[p].Set(GRB.DoubleAttr.Start, 0.0); Console.WriteLine("Closing plant " + p + "\n"); break; } } // Use barrier to solve root relaxation model.GetEnv().Set(GRB.IntParam.Method, GRB.METHOD_BARRIER); // Solve model.Optimize(); // Print solution Console.WriteLine("\nTOTAL COSTS: " + model.Get(GRB.DoubleAttr.ObjVal)); Console.WriteLine("SOLUTION:"); for (int p = 0; p < nPlants; ++p) { if (open[p].Get(GRB.DoubleAttr.X) == 1.0) { Console.WriteLine("Plant " + p + " open:"); for (int w = 0; w < nWarehouses; ++w) { if (transport[w, p].Get(GRB.DoubleAttr.X) > 0.0001) { Console.WriteLine(" Transport " + transport[w, p].Get(GRB.DoubleAttr.X) + " units to warehouse " + w); } } } else { Console.WriteLine("Plant " + p + " closed!"); } } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: sensitivity_cs filename"); return; } try { // Read model GRBEnv env = new GRBEnv(); GRBModel a = new GRBModel(env, args[0]); a.Optimize(); a.GetEnv().Set(GRB.IntParam.OutputFlag, 0); // Extract variables from model GRBVar[] avars = a.GetVars(); for (int i = 0; i < avars.Length; ++i) { GRBVar v = avars[i]; if (v.Get(GRB.CharAttr.VType) == GRB.BINARY) { // Create clone and fix variable GRBModel b = new GRBModel(a); GRBVar bv = b.GetVars()[i]; if (v.Get(GRB.DoubleAttr.X) - v.Get(GRB.DoubleAttr.LB) < 0.5) { bv.Set(GRB.DoubleAttr.LB, bv.Get(GRB.DoubleAttr.UB)); } else { bv.Set(GRB.DoubleAttr.UB, bv.Get(GRB.DoubleAttr.LB)); } b.Optimize(); if (b.Get(GRB.IntAttr.Status) == GRB.Status.OPTIMAL) { double objchg = b.Get(GRB.DoubleAttr.ObjVal) - a.Get(GRB.DoubleAttr.ObjVal); if (objchg < 0) { objchg = 0; } Console.WriteLine("Objective sensitivity for variable " + v.Get(GRB.StringAttr.VarName) + " is " + objchg); } else { Console.WriteLine("Objective sensitivity for variable " + v.Get(GRB.StringAttr.VarName) + " is infinite"); } // Dispose of model b.Dispose(); } } // Dispose of model and env a.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { // Warehouse demand in thousands of units double[] Demand = new double[] { 15, 18, 14, 20 }; // Plant capacity in thousands of units double[] Capacity = new double[] { 20, 22, 17, 19, 18 }; // Fixed costs for each plant double[] FixedCosts = new double[] { 12000, 15000, 17000, 13000, 16000 }; // Transportation costs per thousand units double[,] TransCosts = new double[,] { { 4000, 2000, 3000, 2500, 4500 }, { 2500, 2600, 3400, 3000, 4000 }, { 1200, 1800, 2600, 4100, 3000 }, { 2200, 2600, 3100, 3700, 3200 } }; // Number of plants and warehouses int nPlants = Capacity.Length; int nWarehouses = Demand.Length; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.Set(GRB.StringAttr.ModelName, "facility"); // Plant open decision variables: open[p] == 1 if plant p is open. GRBVar[] open = new GRBVar[nPlants]; for (int p = 0; p < nPlants; ++p) { open[p] = model.AddVar(0, 1, FixedCosts[p], GRB.BINARY, "Open" + p); } // Transportation decision variables: how much to transport from // a plant p to a warehouse w GRBVar[,] transport = new GRBVar[nWarehouses,nPlants]; for (int w = 0; w < nWarehouses; ++w) { for (int p = 0; p < nPlants; ++p) { transport[w,p] = model.AddVar(0, GRB.INFINITY, TransCosts[w,p], GRB.CONTINUOUS, "Trans" + p + "." + w); } } // The objective is to minimize the total fixed and variable costs model.Set(GRB.IntAttr.ModelSense, 1); // Update model to integrate new variables model.Update(); // Production constraints // Note that the right-hand limit sets the production to zero if // the plant is closed for (int p = 0; p < nPlants; ++p) { GRBLinExpr ptot = 0.0; for (int w = 0; w < nWarehouses; ++w) ptot += transport[w,p]; model.AddConstr(ptot <= Capacity[p] * open[p], "Capacity" + p); } // Demand constraints for (int w = 0; w < nWarehouses; ++w) { GRBLinExpr dtot = 0.0; for (int p = 0; p < nPlants; ++p) dtot += transport[w,p]; model.AddConstr(dtot == Demand[w], "Demand" + w); } // Guess at the starting point: close the plant with the highest // fixed costs; open all others // First, open all plants for (int p = 0; p < nPlants; ++p) { open[p].Set(GRB.DoubleAttr.Start, 1.0); } // Now close the plant with the highest fixed cost Console.WriteLine("Initial guess:"); double maxFixed = -GRB.INFINITY; for (int p = 0; p < nPlants; ++p) { if (FixedCosts[p] > maxFixed) { maxFixed = FixedCosts[p]; } } for (int p = 0; p < nPlants; ++p) { if (FixedCosts[p] == maxFixed) { open[p].Set(GRB.DoubleAttr.Start, 0.0); Console.WriteLine("Closing plant " + p + "\n"); break; } } // Use barrier to solve root relaxation model.GetEnv().Set(GRB.IntParam.Method, GRB.METHOD_BARRIER); // Solve model.Optimize(); // Print solution Console.WriteLine("\nTOTAL COSTS: " + model.Get(GRB.DoubleAttr.ObjVal)); Console.WriteLine("SOLUTION:"); for (int p = 0; p < nPlants; ++p) { if (open[p].Get(GRB.DoubleAttr.X) == 1.0) { Console.WriteLine("Plant " + p + " open:"); for (int w = 0; w < nWarehouses; ++w) { if (transport[w,p].Get(GRB.DoubleAttr.X) > 0.0001) { Console.WriteLine(" Transport " + transport[w,p].Get(GRB.DoubleAttr.X) + " units to warehouse " + w); } } } else { Console.WriteLine("Plant " + p + " closed!"); } } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }