static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: feasopt_cs filename"); return; } try { GRBEnv env = new GRBEnv(); GRBModel feasmodel = new GRBModel(env, args[0]); // Create a copy to use FeasRelax feature later */ GRBModel feasmodel1 = new GRBModel(feasmodel); // Clear objective feasmodel.SetObjective(new GRBLinExpr()); // Add slack variables GRBConstr[] c = feasmodel.GetConstrs(); for (int i = 0; i < c.Length; ++i) { char sense = c[i].Get(GRB.CharAttr.Sense); if (sense != '>') { GRBConstr[] constrs = new GRBConstr[] { c[i] }; double[] coeffs = new double[] { -1 }; feasmodel.AddVar(0.0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, constrs, coeffs, "ArtN_" + c[i].Get(GRB.StringAttr.ConstrName)); } if (sense != '<') { GRBConstr[] constrs = new GRBConstr[] { c[i] }; double[] coeffs = new double[] { 1 }; feasmodel.AddVar(0.0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, constrs, coeffs, "ArtP_" + c[i].Get(GRB.StringAttr.ConstrName)); } } feasmodel.Update(); // Optimize modified model feasmodel.Write("feasopt.lp"); feasmodel.Optimize(); // Use FeasRelax feature */ feasmodel1.FeasRelax(GRB.FEASRELAX_LINEAR, true, false, true); feasmodel1.Write("feasopt1.lp"); feasmodel1.Optimize(); // Dispose of model and env feasmodel1.Dispose(); feasmodel.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { GRBEnv env = new GRBEnv("mip1.log"); GRBModel model = new GRBModel(env); // Create variables GRBVar x = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "x"); GRBVar y = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "y"); GRBVar z = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "z"); // Integrate new variables model.Update(); // Set objective: maximize x + y + 2 z model.SetObjective(x + y + 2 * z, GRB.MAXIMIZE); // Add constraint: x + 2 y + 3 z <= 4 model.AddConstr(x + 2 * y + 3 * z <= 4.0, "c0"); // Add constraint: x + y >= 1 model.AddConstr(x + y >= 1.0, "c1"); // Optimize model model.Optimize(); Console.WriteLine(x.Get(GRB.StringAttr.VarName) + " " + x.Get(GRB.DoubleAttr.X)); Console.WriteLine(y.Get(GRB.StringAttr.VarName) + " " + y.Get(GRB.DoubleAttr.X)); Console.WriteLine(z.Get(GRB.StringAttr.VarName) + " " + z.Get(GRB.DoubleAttr.X)); Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal)); // 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.Parameters.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]; } } // 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].UB = 0.0; } model.SetCallback(new tsp_cs(vars)); model.Optimize(); if (model.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); } }
public BalanceOutput BalanceGurobiForGLR(double[] x0, double[,] a, double[,] h, double[] d, double[] technologicLowerBound, double[] technologicUpperBound, double[] metrologicLowerBound, double[] metrologicUpperBound) { try { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); double[] results = new double[x0.Length]; if (inputData.balanceSettings.balanceSettingsConstraints == BalanceSettings.BalanceSettingsConstraints.TECHNOLOGIC) { //Create variables GRBVar[] varsTechnologic = new GRBVar[a.Columns()]; for (int i = 0; i < varsTechnologic.Length; i++) { varsTechnologic[i] = model.AddVar(technologicLowerBound[i], technologicUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i); } //Set objective GRBQuadExpr objTechnologic = new GRBQuadExpr(); for (int i = 0; i < varsTechnologic.Length; i++) { objTechnologic.AddTerm(h[i, i] / 2.0, varsTechnologic[i], varsTechnologic[i]); } for (int i = 0; i < varsTechnologic.Length; i++) { objTechnologic.AddTerm(d[i], varsTechnologic[i]); } model.SetObjective(objTechnologic); //Add constraints GRBLinExpr expr; for (int i = 0; i < a.Rows(); i++) { expr = new GRBLinExpr(); for (int j = 0; j < a.Columns(); j++) { expr.AddTerm(a[i, j], varsTechnologic[j]); } model.AddConstr(expr, GRB.EQUAL, 0.0, "c" + i); } // Optimize model model.Optimize(); //results = new double[varsTechnologic.Length]; for (int i = 0; i < results.Length; i++) { results[i] = varsTechnologic[i].Get(GRB.DoubleAttr.X); } } else { //Create variables GRBVar[] varsMetrologic = new GRBVar[a.Columns()]; for (int i = 0; i < varsMetrologic.Length; i++) { varsMetrologic[i] = model.AddVar(metrologicLowerBound[i], metrologicUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i); } //Set objective GRBQuadExpr objMetrologic = new GRBQuadExpr(); for (int i = 0; i < varsMetrologic.Length; i++) { objMetrologic.AddTerm(h[i, i] / 2.0, varsMetrologic[i], varsMetrologic[i]); } for (int i = 0; i < varsMetrologic.Length; i++) { objMetrologic.AddTerm(d[i], varsMetrologic[i]); } model.SetObjective(objMetrologic); //Add constraints GRBLinExpr expr; for (int i = 0; i < a.Rows(); i++) { expr = new GRBLinExpr(); for (int j = 0; j < a.Columns(); j++) { expr.AddTerm(a[i, j], varsMetrologic[j]); } model.AddConstr(expr, GRB.EQUAL, 0.0, "c" + i); } // Optimize model model.Optimize(); //results = new double[varsMetrologic.Length]; for (int i = 0; i < results.Length; i++) { results[i] = varsMetrologic[i].Get(GRB.DoubleAttr.X); } } model.Dispose(); env.Dispose(); BalanceOutput outb = new BalanceOutput(); var balanceOutputVars = new List <OutputVariables>(); for (int i = 0; i < measuredValues.Count; i++) { InputVariables outputVariable = inputData.BalanceInputVariables[i]; balanceOutputVars.Add(new OutputVariables() { id = outputVariable.id, name = outputVariable.name, value = results[i], source = outputVariable.sourceId, target = outputVariable.destinationId }); } outb.balanceOutputVariables = balanceOutputVars; outb.GlobaltestValue = GTR; outb.Status = "Success"; return(outb); } catch (Exception e) { return(new BalanceOutput { Status = e.Message, }); } }
static void Main(string[] args) { //Deserializar o arquivo Json para o c# //JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); var json = File.ReadAllText("C:\\Users\\ruany\\Documents\\dissertacao\\gerador-instancias\\instanciaT11E8D10F6.json"); Parametros instancia = JsonConvert.DeserializeObject <Parametros>(json); // matrizes que irão guardar as soluções do Relax and Fix double[,,] matriz_RaF_x = new double[instancia.crew, instancia.task, instancia.date]; double[,] matriz_RaF_x3 = new double[instancia.task, instancia.date]; double[,] matriz_RaF_x2 = new double[instancia.task, instancia.date]; double[] matriz_RaF_x4 = new double[instancia.task]; double[,,] matriz_RaF_x5 = new double[instancia.crew, instancia.task, instancia.date]; double[,] matriz_RaF_x6 = new double[instancia.task, instancia.date]; double[,] matriz_RaF_y = new double[instancia.crew, instancia.date]; double[,,] matriz_RaF_z = new double[instancia.crew, instancia.task, instancia.date]; double[,] matriz_RaF_z1 = new double[instancia.crew, instancia.task]; double[,,] matriz_RaF_w = new double[instancia.crew, instancia.technical_place, instancia.date]; double[,,,] matriz_RaF_v = new double[instancia.crew, instancia.technical_place, instancia.technical_place, instancia.date]; double[,,] matriz_RaF_w1 = new double[instancia.crew, instancia.technical_place, instancia.date]; double[,,] matriz_RaF_w2 = new double[instancia.crew, instancia.technical_place, instancia.date]; //tempo por iteração double tempo_iteracao, tempo_total; //status de cada iteração int status_RF; //lista List <double> lista_RF = new List <double>(); double soma_RF = 0; //função Relax and Fix void modelo_RelaxAndFixData(int iteracao) { //Modelo GRBEnv ambiente = new GRBEnv(); GRBModel modelo = new GRBModel(ambiente); //número grande int M = 1000; //Variáveis //fração da tarefa i que o membro de equipe n completa na data j GRBVar[,,] x = new GRBVar[instancia.crew, instancia.task, instancia.date]; for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { x[n, i, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "x_" + n + "_" + i + "_" + j); } } } //fração da tarefa i que é completada na data j GRBVar[,] x3 = new GRBVar[instancia.task, instancia.date]; for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { x3[i, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "x3_" + i + "_" + j); } } //1 se alguma tarefa i é completada na data j GRBVar[,] x2 = new GRBVar[instancia.task, instancia.date]; for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { x2[i, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "x2_" + i + "_" + j); } } //1 se a tarefa i é concluída dentro do horizonte de planejamento GRBVar[] x4 = new GRBVar[instancia.task]; for (int i = 0; i < instancia.task; i++) { x4[i] = modelo.AddVar(0, 1, instancia.c[i] * 2, GRB.CONTINUOUS, "x4_" + i); } //variável fantasma GRBVar[] vf = new GRBVar[instancia.task]; for (int i = 0; i < instancia.task; i++) { vf[i] = modelo.AddVar(1, 1, instancia.c[i] * 2, GRB.BINARY, "vf_" + i); } //1 se o membro de equipe n está trabalhando na tarefa i na data j mas não na data j+1 GRBVar[,,] x5 = new GRBVar[instancia.crew, instancia.task, instancia.date]; for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { x5[n, i, j] = modelo.AddVar(0, 1, 0.1, GRB.CONTINUOUS, "x5_" + n + "_" + i + "_" + j); } } } //1 se parte da tarefa i é completada na data j mas não na data j+1 GRBVar[,] x6 = new GRBVar[instancia.task, instancia.date]; for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { x6[i, j] = modelo.AddVar(0, 1, 0.9, GRB.CONTINUOUS, "x6_" + i + "_" + j); } } //1 se o membro da equipe n vai trabalhar na data j GRBVar[,] y = new GRBVar[instancia.crew, instancia.date]; for (int n = 0; n < instancia.crew; n++) { for (int j = 0; j < instancia.date; j++) { y[n, j] = modelo.AddVar(0, 1, instancia.hours_per_shift, GRB.CONTINUOUS, "y_" + n + "_" + j); } } //1 se membro da equipe n trabalha na tarefa i na data j GRBVar[,,] z = new GRBVar[instancia.crew, instancia.task, instancia.date]; for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { z[n, i, j] = modelo.AddVar(0, 1, 0.5, GRB.CONTINUOUS, "z_" + n + "_" + i + "_" + j); } } } //1 se o membro de equipe n trabalha na tarefa i GRBVar[,] z1 = new GRBVar[instancia.crew, instancia.task]; for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { z1[n, i] = modelo.AddVar(0, 1, 0.1, GRB.CONTINUOUS, "z1_" + n + "_" + i); } } //1 se o membro de equipe n trabalha no local técnico p na data j GRBVar[,,] w = new GRBVar[instancia.crew, instancia.technical_place, instancia.date]; for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { w[n, p, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "w_" + n + "_" + p + "_" + j); } } } //1 se o membro de equipe n precisa de transporte entre o local técnico o e o local q na instancia.date j GRBVar[,,,] v = new GRBVar[instancia.crew, instancia.technical_place, instancia.technical_place, instancia.date]; for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int q = 0; q < instancia.technical_place; q++) { for (int j = 0; j < instancia.date; j++) { v[n, p, q, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "v_" + n + "_" + p + "_" + q + "_" + j); } } } } //se a equipe n precisa de transporte para o local técnico p de outro local técnico na data j GRBVar[,,] w1 = new GRBVar[instancia.crew, instancia.technical_place, instancia.date]; for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { w1[n, p, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "w1_" + n + "_" + p + "_" + j); } } } //se a equipe n precisa de transporte do local técnico p para outro local técnico GRBVar[,,] w2 = new GRBVar[instancia.crew, instancia.technical_place, instancia.date]; for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { w2[n, p, j] = modelo.AddVar(0, 1, 0, GRB.CONTINUOUS, "w2_" + n + "_" + p + "_" + j); } } } //Função objetivo modelo.ModelSense = GRB.MINIMIZE; //Restrições GRBLinExpr exp = 0.0; GRBLinExpr exp2 = 0.0; GRBLinExpr exp3 = 0.0; //Restrições com relação a tarefa //restrição 2 //a tarefa deve ser concluída dentro do horizonte de planejamento for (int i = 0; i < instancia.task; i++) { exp.Clear(); for (int n = 0; n < instancia.crew; n++) { for (int j = 0; j < instancia.date; j++) { exp.AddTerm(1, x[n, i, j]); } } modelo.AddConstr(exp == x4[i], "R2_" + i); } //restrição 3 //o número total de horas por turno não deve ser excedido for (int j = 0; j < instancia.date; j++) { for (int n = 0; n < instancia.crew; n++) { exp.Clear(); exp2.Clear(); exp3.Clear(); for (int i = 0; i < instancia.task; i++) { exp.AddTerm(instancia.c[i], x[n, i, j]); } for (int p = 0; p < instancia.technical_place; p++) { exp2.AddTerm(2 * instancia.tm[p], w[n, p, j]); exp2.AddTerm(-instancia.tm[p], w1[n, p, j]); exp2.AddTerm(-instancia.tm[p], w2[n, p, j]); } for (int p = 0; p < instancia.technical_place; p++) { for (int q = 0; q < instancia.technical_place; q++) { exp3.AddTerm(instancia.tr[p, q], v[n, p, q, j]); } } modelo.AddConstr(exp + exp2 + exp3 <= instancia.hours_per_shift, "R3_" + j + "_" + n); } } //restrição 4 //a soma das frações das tarefas locadas não pode exceder o total para completar a tarefa for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int n = 0; n < instancia.crew; n++) { exp.AddTerm(1, x[n, i, j]); } modelo.AddConstr(x2[i, j] >= exp, "R4_" + i + "_" + j); } } //restrição 5 //soma de das frações dos membros e equipe num dado dia deve ser igual a x3 for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int n = 0; n < instancia.crew; n++) { exp.AddTerm(1, x[n, i, j]); } modelo.AddConstr(x3[i, j] == exp, "R5_" + i + "_" + j); } } //restrição 6 //a tarefa i deve ser completada dentro do horizonte de planejamento se gi=1 for (int i = 0; i < instancia.task; i++) { modelo.AddConstr(x4[i] >= instancia.g[i], "R6_" + i); } //restrição 7 //fração da tarefa que é completada num dado dia não deve exceder X4 for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { modelo.AddConstr(x4[i] >= x[n, i, j], "R7_" + n + "_" + i + "_" + j); } } } //restrição 8 //um membro de equipe não pode ser locado a uma tarefa em um dia em que ele não trabalha for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { modelo.AddConstr(y[n, j] >= z[n, i, j], "R8_" + n + "_" + i + "_" + j); } } } //restrição 9 //se o membro de equipe é locado para uma tarefa então z=1 for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { modelo.AddConstr(z[n, i, j] >= x[n, i, j], "R9_" + n + "_" + i + "_" + j); } } } //restrição 10 //a variável z não pode ser 1 se a equipe n não trabalha num dado dia for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { modelo.AddConstr(z[n, i, j] <= M * x[n, i, j], "R10_" + n + "_" + i + "_" + j); } } } //restrição 11 for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { modelo.AddConstr(z1[n, i] >= z[n, i, j], "R11_" + n + "_" + i + "_" + j); } } } //Restrições de gerenciemanto //restrição 12 //preferencalmente uma tarefa deve concluida pela mesma pessoa que começou trabalhando nela for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date - 1; j++) { modelo.AddConstr(x5[n, i, j] >= z[n, i, j] - z[n, i, j + 1], "R12_" + n + "_" + i + "_" + j); } } } //restrição 13 //uma penalidade será dada ao planejamento se a tarefa i é completada em dias não consecutivos for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date - 1; j++) { modelo.AddConstr(x6[i, j] >= x2[i, j] - x2[i, j + 1], "R13_" + i + "_" + j); } } //restrição 14 //o número mínimo de membros de equipe que podem trabalhar simultaneamente em uma tarefa for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int n = 0; n < instancia.crew; n++) { exp.AddTerm(1, z[n, i, j]); } modelo.AddConstr(exp >= instancia.d1[i] * x2[i, j], "R14_" + i + "_" + j); } } //restrição 15 //o número máximo de membros de equipe que podem trablhar simultaneamente em uma tarefa for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int n = 0; n < instancia.crew; n++) { exp.AddTerm(1, z[n, i, j]); } modelo.AddConstr(exp <= instancia.d2[i] * x2[i, j], "R15_" + i + "_" + j); } } //restrição 16 //número mínimo de membros para trabalhar em um tarefa deve ser respeitado for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { modelo.AddConstr(x[n, i, j] <= x3[i, j] / instancia.d1[i], "R16_" + n + "_" + i + "_" + j); } } } //restrição 17 //membros de equipe não podem trabalhar em dias em que eles não estão disponíveis for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { modelo.AddConstr(z[n, i, j] <= instancia.e[n, j], "R17_" + n + "_" + i + "_" + j); } } } //Restrições com relação a competência //restrição 18 //a combinação do nível de competencias de todos os membros //de equipe deve ser suficiente para cada tarefa for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { for (int k = 0; k < instancia.competencies; k++) { exp.Clear(); for (int n = 0; n < instancia.crew; n++) { exp.AddTerm(instancia.bm3[n, k], z[n, i, j]); } modelo.AddConstr(exp >= x2[i, j] * instancia.bo[i, k] * instancia.level_total, "R18_" + i + "_" + j + "_" + k); } } } //restrição 19 //pelo menos um membro de equipe deve ter nível 3 de competencia para a tarefa i for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { for (int k = 0; k < instancia.competencies; k++) { exp.Clear(); for (int n = 0; n < instancia.crew; n++) { exp.AddTerm(instancia.bm[n, k], z[n, i, j]); } modelo.AddConstr(exp >= x2[i, j] * instancia.bo[i, k], "R19_" + i + "_" + j + "_" + k); } } } //restrição 20 //pelo menos um mebro de equipe tem nível de competencia 3 se vários membros de equipe trabalham na mesma tarefa for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { for (int k = 0; k < instancia.competencies; k++) { exp.Clear(); exp2.Clear(); for (int n = 0; n < instancia.crew; n++) { exp.AddTerm(instancia.bm[n, k], x[n, i, j]); exp2.AddTerm(instancia.bm2[n, k], x[n, i, j]); } modelo.AddConstr(exp >= exp2 * (double)(1 / instancia.d1[i]), "R20_" + i + "_" + j + "_" + k); } } } //Restrições com relação ao transporte //restrição 21 //cada membro de equipe trabalha em um local técnico em que a tarefa está localizada for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int i = 0; i < instancia.task; i++) { exp.AddTerm(instancia.tp[i, p], z[n, i, j]); } modelo.AddConstr(w[n, p, j] <= exp, "R21_" + n + "_" + p + "_" + j); } } } //restrição 22 for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int i = 0; i < instancia.task; i++) { exp.AddTerm(instancia.tp[i, p], z[n, i, j]); } modelo.AddConstr(w[n, p, j] * M >= exp, "R22_" + n + "_" + p + "_" + j); } } } //restrição 23 //o membro de equipe só é transportado entre os locais técnicos que as tarefas dele estão localizadas for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int q = 0; q < instancia.technical_place; q++) { exp.AddTerm(1, v[n, p, q, j]); } modelo.AddConstr(exp <= w[n, p, j] * M, "R23_" + n + "_" + p + "_" + j); } } } //restrição 24 for (int n = 0; n < instancia.crew; n++) { for (int q = 0; q < instancia.technical_place; q++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int p = 0; p < instancia.technical_place; p++) { exp.AddTerm(1, v[n, p, q, j]); } modelo.AddConstr(exp <= w[n, q, j] * M, "R24_" + n + "_" + q + "_" + j); } } } //restrição 25 //se o membro de equipe trabalha em mais do que um local técninco durante o turno for (int n = 0; n < instancia.crew; n++) { for (int q = 0; q < instancia.technical_place; q++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int p = 0; p < instancia.technical_place; p++) { exp.AddTerm(1, v[n, p, q, j]); } modelo.AddConstr(w1[n, q, j] == exp, "R25_" + n + "_" + q + "_" + j); } } } //restrição 26 for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int q = 0; q < instancia.technical_place; q++) { exp.AddTerm(1, v[n, p, q, j]); } modelo.AddConstr(w2[n, p, j] == exp, "R26_" + n + "_" + p + "_" + j); } } } //restrição 27 //cada membro de equipe pode apenas ser transportado de e para cada local técnico uma vez por dia for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { modelo.AddConstr(w1[n, p, j] <= 1, "R27_" + n + "_" + p + "_" + j); } } } //restrição 28 for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { modelo.AddConstr(w2[n, p, j] <= 1, "R28_" + n + "_" + p + "_" + j); } } } //restrição 29 //funcionário será transportado apenas uma vez do e para o depósito for (int n = 0; n < instancia.crew; n++) { for (int j = 0; j < instancia.date; j++) { exp.Clear(); for (int p = 0; p < instancia.technical_place; p++) { exp.AddTerm(2, w[n, p, j]); exp.AddTerm(-1, w1[n, p, j]); exp.AddTerm(-1, w2[n, p, j]); } modelo.AddConstr(exp == 2 * y[n, j], "R29_" + n + "_" + j); } } //variáveis a serem fixadas if (iteracao != 0) { for (int n = 0; n < instancia.crew; n++) { //fixar variável y for (int j = 0; j < iteracao - 1; j++) { y[n, j].Set(GRB.DoubleAttr.LB, matriz_RaF_y[n, j]); y[n, j].Set(GRB.DoubleAttr.UB, matriz_RaF_y[n, j]); //fixar variável z for (int i = 0; i < instancia.task; i++) { z[n, i, j].Set(GRB.DoubleAttr.LB, matriz_RaF_z[n, i, j]); z[n, i, j].Set(GRB.DoubleAttr.UB, matriz_RaF_z[n, i, j]); } } } } //varivais binárias //variável z for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { z[n, i, iteracao].Set(GRB.CharAttr.VType, GRB.BINARY); } } //variável y for (int n = 0; n < instancia.crew; n++) { y[n, iteracao].Set(GRB.CharAttr.VType, GRB.BINARY); } //variável x4 for (int i = 0; i < instancia.task; i++) { x4[i].Set(GRB.CharAttr.VType, GRB.BINARY); } //variável x5 for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < iteracao; j++) { x5[n, i, j].Set(GRB.CharAttr.VType, GRB.BINARY); } } } //variável x6 for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < iteracao; j++) { x6[i, j].Set(GRB.CharAttr.VType, GRB.BINARY); } } //variável z1 for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { z1[n, i].Set(GRB.CharAttr.VType, GRB.BINARY); } } //variável w for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < iteracao; j++) { w[n, p, j].Set(GRB.CharAttr.VType, GRB.BINARY); } } } //variável v for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int q = 0; q < instancia.technical_place; q++) { for (int j = 0; j < iteracao; j++) { v[n, p, q, j].Set(GRB.CharAttr.VType, GRB.BINARY); } } } } //variável w1 for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < iteracao; j++) { w1[n, p, j].Set(GRB.CharAttr.VType, GRB.BINARY); } } } //variável w2 for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < iteracao; j++) { w2[n, p, j].Set(GRB.CharAttr.VType, GRB.BINARY); } } } //otimizar modelo modelo.Set(GRB.DoubleParam.TimeLimit, tempo_iteracao); modelo.Update(); modelo.Optimize(); tempo_total -= modelo.Get(GRB.DoubleAttr.Runtime); //atualizar int solverStatus = modelo.Get(GRB.IntAttr.Status); if (modelo.SolCount == 0 || solverStatus == 3) { status_RF = 999999; return; } else { //salvar a salocao for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { //variável z matriz_RaF_z[n, i, iteracao] = z[n, i, iteracao].X; } //variável y matriz_RaF_y[n, iteracao] = y[n, iteracao].X; } // se estiver na última iteracao salvar nas matizes o valor das variáveis if (iteracao == instancia.date) { //variável x for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { matriz_RaF_x[n, i, j] = x[n, i, j].X; } } } //variável x3 for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { matriz_RaF_x3[i, j] = x3[i, j].X; } } //vairável x2 for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { matriz_RaF_x2[i, j] = x2[i, j].X; } } //variável x4 for (int i = 0; i < instancia.task; i++) { matriz_RaF_x4[i] = x4[i].X; } //variável x5 for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { matriz_RaF_x5[n, i, j] = x5[n, i, j].X; } } } //variável x6 for (int i = 0; i < instancia.task; i++) { for (int j = 0; j < instancia.date; j++) { matriz_RaF_x6[i, j] = x6[i, j].X; } } //variável z1 for (int n = 0; n < instancia.crew; n++) { for (int i = 0; i < instancia.task; i++) { matriz_RaF_z1[n, i] = z1[n, i].X; } } //variável w for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { matriz_RaF_w[n, p, j] = w[n, p, j].X; } } } //variável v for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int q = 0; q < instancia.technical_place; q++) { for (int j = 0; j < instancia.date; j++) { matriz_RaF_v[n, p, q, j] = v[n, p, q, j].X; } } } } //variável w1 for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { matriz_RaF_w1[n, p, j] = w1[n, p, j].X; } } } //variável w2 for (int n = 0; n < instancia.crew; n++) { for (int p = 0; p < instancia.technical_place; p++) { for (int j = 0; j < instancia.date; j++) { matriz_RaF_w2[n, p, j] = w2[n, p, j].X; } } } } } if (iteracao == instancia.date) { double funcaoObjetivo; funcaoObjetivo = modelo.Get(GRB.DoubleAttr.ObjVal); Console.WriteLine("Solução atual:" + funcaoObjetivo.ToString()); lista_RF.Add(funcaoObjetivo); soma_RF += funcaoObjetivo; } } //Relaz and Fix //Stopwatch para contar o tempo Stopwatch relogio = new Stopwatch(); tempo_total = 3600; relogio.Start(); for (int j = 0; j < instancia.date; j++) { status_RF = 0; tempo_iteracao = tempo_total / (instancia.date - j + 1); modelo_RelaxAndFixData(j); if (status_RF != 0) { lista_RF.Add(99999999); soma_RF += 99999999; } } relogio.Stop(); Console.WriteLine("tempo total de:" + (relogio.ElapsedMilliseconds / 1000).ToString() + "segundos"); Console.ReadKey(); }
public GurobiSolver(Crossword crossword) { var wordLengthHistogram = new Dictionary <int, int>() { { 3, 18 }, { 4, 24 }, { 5, 20 }, { 6, 18 }, { 7, 12 }, { 8, 4 }, { 9, 4 }, }; const int maxWordLength = 9; int sizeY = crossword.Grid.GetLength(0); int sizeX = crossword.Grid.GetLength(1); int amountQuestions = (int)Math.Round(0.22 * sizeX * sizeY); GRBEnv env = new GRBEnv(); GRBModel m = new GRBModel(env); // 0 = letter, 1 = question GRBVar[,] fields = new GRBVar[sizeY, sizeX]; // 0 = right, 1 = down GRBVar[,] questionType = new GRBVar[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" + x + "_" + y); questionType[y, x] = m.AddVar(0, 1, 0, GRB.BINARY, "QType" + x + "_" + y); } } } GRBLinExpr allFieldsSum = new GRBLinExpr(); // count word lengths (to compare with histogram) var lengths = new Dictionary <int, GRBLinExpr>(); foreach (var l in wordLengthHistogram.Keys) { lengths.Add(l, new GRBLinExpr()); } var partOfAWord = new GRBLinExpr[sizeY, sizeX]; for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { partOfAWord[y, x] = new GRBLinExpr(); } } for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { allFieldsSum += fields[y, x]; foreach (var l in wordLengthHistogram.Keys) { if (x + l < sizeX) { // + 1 if the following fields are all words and the last one is not a word (question or outside grid) var wordCount = new GRBLinExpr(); for (int i = 1; i <= l; i++) { wordCount += fields[y, x + i]; } // last field is question or outside? var lastFieldIsNoWord = m.AddVar(0, 1, 0, GRB.BINARY, "lastFieldIsNoWord" + y + "_" + x + "_" + l); if (x + l + 1 < sizeX) { m.AddConstr(lastFieldIsNoWord == fields[y, x + l + 1], "lastFieldIsInGridAndIsQuestion" + y + "_" + x + "_" + l); } else { m.AddConstr(lastFieldIsNoWord == 1, "lastFieldOutsideGrid" + y + "_" + x + "_" + l); } // https://cs.stackexchange.com/questions/51025/cast-to-boolean-for-integer-linear-programming var hasCorrectWordCount = m.AddVar(0, 1, 0, GRB.BINARY, "hasCorrect" + y + "_" + x + "_" + l); var hcTemp = m.AddVar(0, 1, 0, GRB.BINARY, "hasCorrectTemp" + y + "_" + x + "_" + l); var worddiff = wordCount - l; m.AddConstr(-sizeX * hasCorrectWordCount <= worddiff, "ToBoolean" + y + "_" + x + "_" + l + "_1"); m.AddConstr(worddiff <= sizeX * hasCorrectWordCount, "ToBoolean" + y + "_" + x + "_" + l + "_2"); m.AddConstr(0.001 * hasCorrectWordCount - (sizeX + 0.001) * hcTemp <= worddiff, "ToBoolean" + y + "_" + x + "_" + l + "_3"); m.AddConstr(worddiff <= -0.001 * hasCorrectWordCount + (sizeX + 0.001) * (1 - hcTemp), "ToBoolean" + y + "_" + x + "_" + l + "_4"); // firstFieldIsQuestion AND questionIsHorizontal AND hasCorrectWordCount AND lastFieldIsNoWord var allConditionsMet = m.AddVar(0, 1, 0, GRB.BINARY, "allCondsMet" + y + "_" + x + "_" + l); var condVal = fields[y, x] + (1 - questionType[y, x]) + hasCorrectWordCount + lastFieldIsNoWord - 3; m.AddConstr(allConditionsMet >= condVal, "AllConditionsAND" + y + "_" + x + "_" + l + "_1"); m.AddConstr(allConditionsMet <= fields[y, x], "AllConditionsAND" + y + "_" + x + "_" + l + "_2"); m.AddConstr(allConditionsMet <= (1 - questionType[y, x]), "AllConditionsAND" + y + "_" + x + "_" + l + "_3"); m.AddConstr(allConditionsMet <= hasCorrectWordCount, "AllConditionsAND" + y + "_" + x + "_" + l + "_4"); m.AddConstr(allConditionsMet <= lastFieldIsNoWord, "AllConditionsAND" + y + "_" + x + "_" + l + "_5"); lengths[l] += allConditionsMet; // If all conditions are met, all letters are part of a word for (int i = 1; i <= l; i++) { partOfAWord[y, x + i] += allConditionsMet; } } if (y + l < sizeY) { // + 1 if the following fields are all words and the last one is not a word (question or outside grid) var wordCount = new GRBLinExpr(); for (int i = 1; i <= l; i++) { wordCount += fields[y + i, x]; } // last field is question or outside? var lastFieldIsNoWord = m.AddVar(0, 1, 0, GRB.BINARY, "lastFieldIsNoWord" + y + "_" + x + "_" + l); if (y + l + 1 < sizeY) { m.AddConstr(lastFieldIsNoWord == fields[y + l + 1, x], "lastFieldIsInGridAndIsQuestion" + y + "_" + x + "_" + l); } else { m.AddConstr(lastFieldIsNoWord == 1, "lastFieldOutsideGrid" + y + "_" + x + "_" + l); } // https://cs.stackexchange.com/questions/51025/cast-to-boolean-for-integer-linear-programming var hasCorrectWordCount = m.AddVar(0, 1, 0, GRB.BINARY, "hasCorrect" + y + "_" + x + "_" + l); var hcTemp = m.AddVar(0, 1, 0, GRB.BINARY, "hasCorrectTemp" + y + "_" + x + "_" + l); var worddiff = wordCount - l; m.AddConstr(-sizeY * hasCorrectWordCount <= worddiff, "ToBoolean" + y + "_" + x + "_" + l + "_1"); m.AddConstr(worddiff <= sizeY * hasCorrectWordCount, "ToBoolean" + y + "_" + x + "_" + l + "_2"); m.AddConstr(0.001 * hasCorrectWordCount - (sizeY + 0.001) * hcTemp <= worddiff, "ToBoolean" + y + "_" + x + "_" + l + "_3"); m.AddConstr(worddiff <= -0.001 * hasCorrectWordCount + (sizeY + 0.001) * (1 - hcTemp), "ToBoolean" + y + "_" + x + "_" + l + "_4"); // firstFieldIsQuestion AND questionIsHorizontal AND hasCorrectWordCount AND lastFieldIsNoWord var allConditionsMet = m.AddVar(0, 1, 0, GRB.BINARY, "allCondsMet" + y + "_" + x + "_" + l); var condVal = fields[y, x] + (questionType[y, x]) + hasCorrectWordCount + lastFieldIsNoWord - 3; m.AddConstr(allConditionsMet >= condVal, "AllConditionsAND" + y + "_" + x + "_" + l + "_1"); m.AddConstr(allConditionsMet <= fields[y, x], "AllConditionsAND" + y + "_" + x + "_" + l + "_2"); m.AddConstr(allConditionsMet <= (questionType[y, x]), "AllConditionsAND" + y + "_" + x + "_" + l + "_3"); m.AddConstr(allConditionsMet <= hasCorrectWordCount, "AllConditionsAND" + y + "_" + x + "_" + l + "_4"); m.AddConstr(allConditionsMet <= lastFieldIsNoWord, "AllConditionsAND" + y + "_" + x + "_" + l + "_5"); lengths[l] += allConditionsMet; // If all conditions are met, all letters are part of a word for (int i = 1; i <= l; i++) { partOfAWord[y + i, x] += allConditionsMet; } } } // max word count if (x + maxWordLength < sizeX) { var maxWordCount = new GRBLinExpr(); var range = maxWordLength + 1; if (x + range == sizeX) { range--; } for (int i = 0; i < maxWordLength + 1; i++) { maxWordCount += 1 - fields[y, x + i]; } m.AddConstr(maxWordCount <= maxWordLength, "maxWordsX" + y + "_" + x); } if (y + maxWordLength < sizeY) { var maxWordCount = new GRBLinExpr(); var range = maxWordLength + 1; if (y + range == sizeY) { range--; } for (int i = 0; i < maxWordLength + 1; i++) { maxWordCount += 1 - fields[y + i, x]; } m.AddConstr(maxWordCount <= maxWordLength, "maxWordsY" + y + "_" + x); } } } // All non-question fields have to belong to a word for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { m.AddConstr(1 - fields[y, x] <= partOfAWord[y, x], "NonQuestionsToWords" + y + "_" + x + "_1"); m.AddConstr(1 - fields[y, x] >= partOfAWord[y, x] * 0.5, "NonQuestionsToWords" + y + "_" + x + "_2"); } } // after a question, no word of length 1 or 2 is allowed for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { if (x < sizeX - 3) { // if there's a question AND it's pointing right THEN sum(fields[y, x+1/2/3]) = 0 var minLetters = 3 - (fields[y, x + 1] + fields[y, x + 2] + fields[y, x + 3]); m.AddConstr(fields[y, x] + (1 - questionType[y, x]) - 1 <= minLetters * (1d / 3d), "AfterRightQuestionMin2Letters" + y + "_" + x); } else { m.AddConstr(questionType[y, x] == 1, "NoRightQuestionAtRightBorder" + y + "_" + x); } if (y < sizeY - 3) { // if there's a question AND it's pointing down THEN sum(fields[y+1/2/3, x]) = 0 var minLetters = 3 - (fields[y + 1, x] + fields[y + 2, x] + fields[y + 3, x]); m.AddConstr(fields[y, x] + questionType[y, x] - 1 <= minLetters * (1d / 3d), "AfterDownQuestionMin2Letters" + y + "_" + x); } else if (x < sizeX - 3) { m.AddConstr(questionType[y, x] == 0, "NoDownQuestionAtBottomBorder" + y + "_" + x); } else { m.AddConstr(fields[y, x] == 0, "OnlyWordsInBottomrightCorner" + y + "_" + x); } } } // Objective: // questions should be around ~22% (allFieldsSum ~= amountQuestions) var amountOfQuestionsRating = m.AddVar(0, sizeX * sizeY - amountQuestions, 0, GRB.INTEGER, "amountOfQuestionsRating"); var amountOfQuestionsAbsInput = m.AddVar(-amountQuestions, sizeX * sizeY - amountQuestions, 0, GRB.INTEGER, "amountOfQuestionsAbsInput"); m.AddConstr(amountOfQuestionsAbsInput == allFieldsSum - amountQuestions); m.AddGenConstrAbs(amountOfQuestionsRating, amountOfQuestionsAbsInput, "amountOfQuestionsAbs"); /*int tolerance = (int)(amountQuestions * 0.1); * m.AddConstr(allFieldsSum - amountQuestions >= -tolerance); * m.AddConstr(allFieldsSum - amountQuestions <= tolerance);*/ // as many partOfAWord == 2 as possible var manyCrossedWords = new GRBLinExpr(); for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { manyCrossedWords += partOfAWord[y, x]; } } // ideal histogram comparison var wordHistogramDifferences = new GRBQuadExpr(); foreach (var wl in wordLengthHistogram.Keys) { var diff = (wordLengthHistogram[wl] - lengths[wl]) * 2; wordHistogramDifferences += diff * diff; } // question field clusters var clusterPenalty = new GRBLinExpr(); for (int y = 0; y < sizeY - 2; y++) { for (int x = 0; x < sizeX - 2; x++) { var clusterTotal = new GRBLinExpr(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { clusterTotal += fields[y + i, x + j]; } } var varClusterTotalPenalty = m.AddVar(0, 7, 0, GRB.INTEGER, "varClusterTotalPenalty" + y + "_" + x); m.AddConstr(varClusterTotalPenalty >= clusterTotal - 2); clusterPenalty += varClusterTotalPenalty; } } //amountOfQuestionsRating * (100d / sizeX / sizeY) + manyCrossedWords + + wordHistogramDifferences // clusterPenalty * 100 m.SetObjective(amountOfQuestionsRating * (100d / sizeX / sizeY) + clusterPenalty * 100 + wordHistogramDifferences + manyCrossedWords, GRB.MINIMIZE); m.SetCallback(new GRBMipSolCallback(crossword, fields, questionType, null)); m.Optimize(); m.ComputeIIS(); m.Write("model.ilp"); m.Dispose(); env.Dispose(); }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Amount each worker is paid to work one shift double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[,] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.Set(GRB.StringAttr.ModelName, "assignment"); // Assignment variables: x[w][s] == 1 if worker w is assigned // to shift s. Since an assignment model always produces integer // solutions, we use continuous variables and solve as an LP. GRBVar[,] x = new GRBVar[nWorkers,nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w,s] = model.AddVar(0, availability[w,s], pay[w], GRB.CONTINUOUS, Workers[w] + "." + Shifts[s]); } } // The objective is to minimize the total pay costs model.Set(GRB.IntAttr.ModelSense, 1); // Update model to integrate new variables model.Update(); // Constraint: assign exactly shiftRequirements[s] workers // to each shift s LinkedList<GRBConstr> reqCts = new LinkedList<GRBConstr>(); for (int s = 0; s < nShifts; ++s) { GRBLinExpr lhs = 0.0; for (int w = 0; w < nWorkers; ++w) lhs += x[w,s]; GRBConstr newCt = model.AddConstr(lhs == shiftRequirements[s], Shifts[s]); reqCts.AddFirst(newCt); } // Optimize model.Optimize(); int status = model.Get(GRB.IntAttr.Status); if (status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is unbounded"); return; } if (status == GRB.Status.OPTIMAL) { Console.WriteLine("The optimal objective is " + model.Get(GRB.DoubleAttr.ObjVal)); return; } if ((status != GRB.Status.INF_OR_UNBD) && (status != GRB.Status.INFEASIBLE)) { Console.WriteLine("Optimization was stopped with status " + status); return; } // Add slack variables to make the model feasible Console.WriteLine("The model is infeasible; adding slack variables"); // Set original objective coefficients to zero model.SetObjective(new GRBLinExpr()); // Add a new slack variable to each shift constraint so that the shifts // can be satisfied LinkedList<GRBVar> slacks = new LinkedList<GRBVar>(); foreach (GRBConstr c in reqCts) { GRBColumn col = new GRBColumn(); col.AddTerm(1.0, c); GRBVar newvar = model.AddVar(0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, col, c.Get(GRB.StringAttr.ConstrName) + "Slack"); slacks.AddFirst(newvar); } // Solve the model with slacks model.Optimize(); status = model.Get(GRB.IntAttr.Status); if ((status == GRB.Status.INF_OR_UNBD) || (status == GRB.Status.INFEASIBLE) || (status == GRB.Status.UNBOUNDED)) { Console.WriteLine("The model with slacks cannot be solved " + "because it is infeasible or unbounded"); return; } if (status != GRB.Status.OPTIMAL) { Console.WriteLine("Optimization was stopped with status " + status); return; } Console.WriteLine("\nSlack values:"); foreach (GRBVar sv in slacks) { if (sv.Get(GRB.DoubleAttr.X) > 1e-6) { Console.WriteLine(sv.Get(GRB.StringAttr.VarName) + " = " + sv.Get(GRB.DoubleAttr.X)); } } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { GRBEnv env = new GRBEnv("qp.log"); GRBModel model = new GRBModel(env); // Create variables GRBVar x = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "x"); GRBVar y = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "y"); GRBVar z = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "z"); // Integrate new variables model.Update(); // Set objective GRBQuadExpr obj = x*x + x*y + y*y + y*z + z*z; model.SetObjective(obj); // Add constraint: x + 2 y + 3 z >= 4 model.AddConstr(x + 2 * y + 3 * z >= 4.0, "c0"); // Add constraint: x + y >= 1 model.AddConstr(x + y >= 1.0, "c1"); // Optimize model model.Optimize(); Console.WriteLine(x.Get(GRB.StringAttr.VarName) + " " + x.Get(GRB.DoubleAttr.X)); Console.WriteLine(y.Get(GRB.StringAttr.VarName) + " " + y.Get(GRB.DoubleAttr.X)); Console.WriteLine(z.Get(GRB.StringAttr.VarName) + " " + z.Get(GRB.DoubleAttr.X)); Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal) + " " + obj.Value); // Change variable types to integer x.Set(GRB.CharAttr.VType, GRB.INTEGER); y.Set(GRB.CharAttr.VType, GRB.INTEGER); z.Set(GRB.CharAttr.VType, GRB.INTEGER); // Optimize model model.Optimize(); Console.WriteLine(x.Get(GRB.StringAttr.VarName) + " " + x.Get(GRB.DoubleAttr.X)); Console.WriteLine(y.Get(GRB.StringAttr.VarName) + " " + y.Get(GRB.DoubleAttr.X)); Console.WriteLine(z.Get(GRB.StringAttr.VarName) + " " + z.Get(GRB.DoubleAttr.X)); Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal) + " " + obj.Value); // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public override Schedule Generate(Scenario scenario, FilledBaseline baseline = null) { var opportunities = scenario.Projects.Where(p => p is Opportunity).ToArray(); var batches = scenario.Projects.SelectMany(p => p.Batches).ToArray(); var batchesBothLines = batches.Where(b => b.Compatibility == Batch.LineCompatibility.Both).ToArray(); var batchesLine1 = batches.Where(b => b.Compatibility == Batch.LineCompatibility.Line1).ToArray(); var batchesLine2 = batches.Where(b => b.Compatibility == Batch.LineCompatibility.Line2).ToArray(); int bBc = batchesBothLines.Count(); var earliestDate = scenario.Projects.Min(p => p.DeliveryDate); var lastDate = scenario.Projects.Max(p => p.DeliveryDate.AddDays(7 * p.Batches.Count())).AddDays(7 * 3); // add an additional buffer of 3 weeks. double maxDays = (lastDate - earliestDate).Days; var maxWeek = maxDays / 7 + 2; const int weeksBuffer = 3; const double numericScale = 100d; const double delayPenaltyMultiplier = 0.01; // 1% of revenue per week const double interestPenaltyMultiplier = (0.045 / 52.14); // 4.5% / 52.14 * (revenue – margin) var env = new GRBEnv(); env.Set(GRB.IntParam.UpdateMode, 1); env.Set(GRB.IntParam.LogToConsole, 1); //env.Set(GRB.IntParam.ScaleFlag, 2); //env.Set(GRB.IntParam.Presolve, 0); //env.Set(GRB.DoubleParam.TimeLimit, _config.TimeLimit.Value); //env.Set(GRB.DoubleParam.MIPGap, 0.02); var m = new GRBModel(env); // decide: which batch is when, on which line // [batch, time] var varBatchTimeLine1 = m.AddVars(bBc + batchesLine1.Count(), bBc + batchesLine1.Count(), 0, 1, GRB.BINARY, "varBatchTimeLine1"); var varBatchTimeLine2 = m.AddVars(bBc + batchesLine2.Count(), bBc + batchesLine2.Count(), 0, 1, GRB.BINARY, "varBatchTimeLine2"); // what are the time differences between times var varBatchTimeDiffsLine1 = m.AddVars(bBc + batchesLine1.Count() - 1, 0, maxDays, GRB.CONTINUOUS, "varBatchTimeDiffsLine1"); var varBatchTimeDiffsLine2 = m.AddVars(bBc + batchesLine2.Count() - 1, 0, maxDays, GRB.CONTINUOUS, "varBatchTimeDiffsLine2"); var varLineDecision = m.AddVars(bBc, 0, 1, GRB.BINARY, "varLineDecision"); // 0 = Line1, 1 = Line2 // make stupid solution: // assign fixed projects, set the rest as unused m.Update(); for (int l = 0; l < 2; l++) { var line = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2; var diffs = l == 0 ? varBatchTimeDiffsLine1 : varBatchTimeDiffsLine2; for (int i = 0; i < diffs.GetLength(0); i++) { diffs[i].Set(GRB.DoubleAttr.Start, 0); } //m.AddConstr(diffs[i] == 0, "initial solution diffs"); int lineT = 0; for (int bi = bBc; bi < line.GetLength(0); bi++) { var batch = (l == 0 ? batchesLine1 : batchesLine2)[bi - bBc]; bool isFixedProject = scenario.Projects.First(p => p.Batches.Contains(batch)) is FixedProject; if (isFixedProject) { line[bi, lineT].Set(GRB.DoubleAttr.Start, 1); //m.AddConstr(line[bi, lineT] == 1, "assign batches of project in succession"); for (int j = 0; j < line.GetLength(1); j++) { if (j != lineT) { line[bi, j].Set(GRB.DoubleAttr.Start, 0); } } //m.AddConstr(line[bi, j] == 0, "initial solution"); lineT++; } else { for (int j = 0; j < line.GetLength(1); j++) { line[bi, j].Set(GRB.DoubleAttr.Start, 0); } //m.AddConstr(line[bi, j] == 0, "initial solution"); } } // make zeros also for both line batches for (int i = 0; i < bBc; i++) { for (int j = 0; j < line.GetLength(1); j++) { line[i, j].Set(GRB.DoubleAttr.Start, 0); } } //m.AddConstr(line[i, j] == 0, "initial solution"); } // line constraints: // assign batch only once (constraint for single lines then both lines) // if it's a fixed project though, then it must be allocated for (int l = 0; l < 2; l++) { var line = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2; for (int bi = bBc; bi < line.GetLength(0); bi++) { var batchTotal = new GRBLinExpr(); for (int t = 0; t < line.GetLength(1); t++) { batchTotal += line[bi, t]; } var batch = (l == 0 ? batchesLine1 : batchesLine2)[bi - bBc]; bool isFixedProject = scenario.Projects.First(p => p.Batches.Contains(batch)) is FixedProject; if (!isFixedProject) { m.AddConstr(batchTotal <= 1, "assign batch only once"); } else { m.AddConstr(batchTotal == 1, "assign batch exactly once"); } } } for (int bi = 0; bi < bBc; bi++) { var batchTotal = new GRBLinExpr(); for (int t = 0; t < varBatchTimeLine1.GetLength(1); t++) { batchTotal += varBatchTimeLine1[bi, t]; } for (int t = 0; t < varBatchTimeLine2.GetLength(1); t++) { batchTotal += varBatchTimeLine2[bi, t]; } var batch = batchesBothLines[bi]; bool isFixedProject = scenario.Projects.First(p => p.Batches.Contains(batch)) is FixedProject; if (!isFixedProject) { m.AddConstr(batchTotal <= 1, "assign batch only once"); } else { m.AddConstr(batchTotal == 1, "assign batch exactly once"); } } // a time slot can only be used once on each line for (int l = 0; l < 2; l++) { var line = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2; for (int t = 0; t < line.GetLength(1); t++) { var timeTotal = new GRBLinExpr(); for (int bi = 0; bi < line.GetLength(0); bi++) { timeTotal += line[bi, t]; } m.AddConstr(timeTotal <= 1, "assign time slot only once on line " + (l + 1).ToString()); } } // for all batches which aren't assigned to a line yet, limit the allocation of yet unassigned batches of a project to one line // TODO: If project has e.g. line1 and both lines, limit both lines to line 1? for (int pi = 0; pi < scenario.Projects.Count(); pi++) { var p = scenario.Projects[pi]; if (!p.Batches.Any(b => b.Compatibility == Batch.LineCompatibility.Both)) { continue; } int lineRestriction = -1; if (p.Batches.Any(b => b.Compatibility != Batch.LineCompatibility.Both)) { lineRestriction = p.Batches.First(b => b.Compatibility != Batch.LineCompatibility.Both).Compatibility == Batch.LineCompatibility.Line1 ? 0 : 1; } int i_prev = -1; for (int j = 0; j < p.Batches.Count(); j++) { if (p.Batches[j].Compatibility != Batch.LineCompatibility.Both) { continue; } var i = batchesBothLines.IndexOf(p.Batches[j]); if (lineRestriction == -1) { if (i_prev != -1) { m.AddConstr(varLineDecision[i] == varLineDecision[i_prev], "lineDecisionRestrictionAllSame"); } } else { // if there are other batches on this project which are already on a specific line, limit to the same line m.AddConstr(varLineDecision[i] == lineRestriction, "lineDecisionRestrictionSpecific"); } i_prev = i; } } // for each project, either all or no batches must be assigned var totalBatchesOfProject = new Dictionary <Project, List <GRBLinExpr> >(); foreach (var p in scenario.Projects) { var allBatches = new List <GRBLinExpr>(); // gather the total of all batches GRBLinExpr previousBatchTotal = null; for (int bi = 0; bi < p.Batches.Count(); bi++) { var b = p.Batches[bi]; var batchTotal = new GRBLinExpr(); if (b.Compatibility == Batch.LineCompatibility.Line1) { var bIndex = bBc + batchesLine1.IndexOf(b); for (int ti = 0; ti < varBatchTimeLine1.GetLength(1); ti++) { batchTotal += varBatchTimeLine1[bIndex, ti]; } } else if (b.Compatibility == Batch.LineCompatibility.Line2) { var bIndex = bBc + batchesLine2.IndexOf(b); for (int ti = 0; ti < varBatchTimeLine2.GetLength(1); ti++) { batchTotal += varBatchTimeLine2[bIndex, ti]; } } else { var bIndex = batchesBothLines.IndexOf(b); for (int t = 0; t < varBatchTimeLine1.GetLength(1); t++) { batchTotal += varBatchTimeLine1[bIndex, t]; } for (int t = 0; t < varBatchTimeLine2.GetLength(1); t++) { batchTotal += varBatchTimeLine2[bIndex, t]; } } // the sum of this batch over all times (0 or 1) has to be the same as the sum of the previous one if (bi > 0) { //m.AddConstr(previousBatchTotal == batchTotal, "allBatchesAllocatedOrNot"); } previousBatchTotal = batchTotal; allBatches.Add(batchTotal); } totalBatchesOfProject.Add(p, allBatches); } // Tbd: Only half of the batch slots of line 1 may be occupied. Sometimes existst as internal projects. // fill gap between 50% and internal projects, monthly resolution // gather the time of time slots GRBLinExpr[] startTimesLine1 = new GRBLinExpr[varBatchTimeLine1.GetLength(1)]; GRBLinExpr[] startTimesLine2 = new GRBLinExpr[varBatchTimeLine2.GetLength(1)]; var varStartTimesLine1 = m.AddVars(startTimesLine1.Count(), 0, maxDays, GRB.CONTINUOUS, "varStartTimesLine1"); var varStartTimesLine2 = m.AddVars(startTimesLine2.Count(), 0, maxDays, GRB.CONTINUOUS, "varStartTimesLine2"); for (int l = 0; l < 2; l++) { var batchLine = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2; var startTimes = l == 0 ? startTimesLine1 : startTimesLine2; var batchesLine = l == 0 ? batchesLine1 : batchesLine2; var batchTimeDiffs = l == 0 ? varBatchTimeDiffsLine1 : varBatchTimeDiffsLine2; for (int t = 0; t < batchLine.GetLength(1); t++) { startTimes[t] = new GRBLinExpr(); // sum up all durations and buffer times before this time instance for (int previous_t = 0; previous_t < t; previous_t++) { var duration_prev_t = new GRBLinExpr(); for (int bi = 0; bi < batchLine.GetLength(0); bi++) { var batch = bi < bBc ? batchesBothLines[bi] : batchesLine[bi]; var duration = batch.UsedWorkHours / 24d; duration_prev_t += batchLine[bi, previous_t] * duration; } duration_prev_t += batchTimeDiffs[previous_t]; startTimes[t] += duration_prev_t; } } var varStartTime = l == 0 ? varStartTimesLine1 : varStartTimesLine2; for (int i = 0; i < varStartTime.Count(); i++) { m.AddConstr(varStartTime[i] == startTimes[i], "varStartTimeAssignment"); } } // gather the start time of the batches var varStartTimesBatches1 = m.AddVars(varBatchTimeLine1.GetLength(0), 0, maxDays, GRB.CONTINUOUS, "varBatchStartTimesLine1"); var varStartTimesBatches2 = m.AddVars(varBatchTimeLine2.GetLength(0), 0, maxDays, GRB.CONTINUOUS, "varBatchStartTimesLine2"); for (int l = 0; l < 2; l++) { var batchLine = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2; var batchStartTimes = l == 0 ? varStartTimesBatches1 : varStartTimesBatches2; var batchesLine = l == 0 ? batchesLine1 : batchesLine2; var varStartTimes = l == 0 ? varStartTimesLine1 : varStartTimesLine2; for (int bi = 0; bi < batchLine.GetLength(0); bi++) { // make the batch take the value of its time slot for (int ti = 0; ti < batchLine.GetLength(1); ti++) { m.AddConstr(batchStartTimes[bi] <= varStartTimes[ti] + maxDays * (1 - batchLine[bi, ti]), "batchTimeAssignment"); m.AddConstr(batchStartTimes[bi] >= varStartTimes[ti] - maxDays * (1 - batchLine[bi, ti]), "batchTimeAssignment"); } } } // scheduling formulation for (int l = 0; l < 2; l++) { var varBatchStartTimes = l == 0 ? varStartTimesBatches1 : varStartTimesBatches2; var line = batchesBothLines.ToList(); line.AddRange(l == 0 ? batchesLine1 : batchesLine2); for (int bi1 = 0; bi1 < line.Count() - 1; bi1++) { var batch1 = line[bi1]; var o1_exists = opportunities.FirstOrDefault(o => o.Batches.Contains(batch1)); var oi1 = o1_exists != null ? (1 - totalBatchesOfProject[o1_exists][0]) : new GRBLinExpr(); var s1 = varBatchStartTimes[bi1]; var bothLineSlack1 = (bi1 < bBc) ? (l == 0 ? varLineDecision[bi1] - 0 : 1 - varLineDecision[bi1]) : new GRBLinExpr(); for (int bi2 = bi1 + 1; bi2 < line.Count(); bi2++) { var batch2 = line[bi2]; var o2_exists = opportunities.FirstOrDefault(o => o.Batches.Contains(batch2)); var oi2 = o2_exists != null ? (1 - totalBatchesOfProject[o1_exists][0]) : new GRBLinExpr(); var s2 = varBatchStartTimes[bi2]; var bothLineSlack2 = (bi2 < bBc) ? (l == 0 ? varLineDecision[bi2] - l : l - varLineDecision[bi2]) : new GRBLinExpr(); // S1 - E2 >= 0 OR S2 - E1 >= 0 // IF both batches are used var decisionVar = m.AddVar(0, 1, GRB.BINARY, "schedulingORvar"); var opportunityNotUsedSlack = oi1 + oi2; var varBothLinesLineDecisionSlack = bothLineSlack1 + bothLineSlack2; // LineDecisionSlack for both lines batches, i.e. if a bothline batch is used, don't restrict unused line. m.AddConstr(s1 - (s2 + batch2.UsedWorkHours / 24d) >= -maxDays * (decisionVar + opportunityNotUsedSlack + varBothLinesLineDecisionSlack), "batchesScheduling"); m.AddConstr(s2 - (s1 + batch1.UsedWorkHours / 24d) >= -maxDays * (1 - decisionVar + opportunityNotUsedSlack + varBothLinesLineDecisionSlack), "batchesScheduling"); } } } // Maximize the margin (including delay and interest penalties) and the workload // Only the delivery of the first batch is really important. The rest is less important. var margin = new GRBLinExpr(); var delays = new List <GRBLinExpr>(); var interests = new List <GRBLinExpr>(); var weekValues = new List <GRBLinExpr>(); var weekDiffs = new List <GRBLinExpr>(); foreach (var p in scenario.Projects) { // if the project is used add the margin if (p is Opportunity) { margin += totalBatchesOfProject[p][0] * p.Margin * (1d / numericScale); } else { margin += p.Margin / numericScale; } // deduct the delay penalty for each batch. var startDayOfProject = (p.DeliveryDate - earliestDate).TotalDays; var varMaxedValue = m.AddVars(p.Batches.Count(), 0, maxWeek, GRB.CONTINUOUS, "penaltyIndicator" + p.Description); //var varDecisionVar = m.AddVars(p.Batches.Count(), 0, 1, GRB.BINARY, "penaltyIndicator" + p.Description); //m.Update(); GRBLinExpr previousWeekValue = new GRBLinExpr(); for (int pbi = 0; pbi < p.Batches.Count(); pbi++) { var b = p.Batches[pbi]; // compare the minimal batch time (3 + 1 weeks) to the actual delivery time GRBLinExpr weekValue; if (batchesLine1.Contains(b)) { var bi = batchesLine1.IndexOf(b) + bBc; weekValue = varStartTimesBatches1[bi] / 7d; } else if (batchesLine2.Contains(b)) { var bi = batchesLine2.IndexOf(b) + bBc; weekValue = varStartTimesBatches2[bi] / 7d; } else { var bi = batchesBothLines.IndexOf(b); // create a new var var bothLineWeekVar = m.AddVar(0, maxWeek, GRB.CONTINUOUS, "weekValueBothLines"); //m.Update(); m.AddConstr(bothLineWeekVar >= varStartTimesBatches1[bi] / 7d - (varLineDecision[bi]) * maxWeek, "weekValueBothLinesDefinitionByConstraints"); m.AddConstr(bothLineWeekVar <= varStartTimesBatches1[bi] / 7d + (varLineDecision[bi]) * maxWeek, "weekValueBothLinesDefinitionByConstraints"); m.AddConstr(bothLineWeekVar >= varStartTimesBatches2[bi] / 7d - (1 - varLineDecision[bi]) * maxWeek, "weekValueBothLinesDefinitionByConstraints"); m.AddConstr(bothLineWeekVar <= varStartTimesBatches2[bi] / 7d + (1 - varLineDecision[bi]) * maxWeek, "weekValueBothLinesDefinitionByConstraints"); weekValue = bothLineWeekVar; } if (true || pbi < p.Batches.Count() - 1) { // for positive difference add delay penalty, for negative difference add interest penalty // x = opportunity used ? x : 0 // var = max(0, x) // margin += var * delay // margin += (x - var) * interest var plannedWeek = startDayOfProject / 7d + pbi * (weeksBuffer + 1); GRBLinExpr weekDiff; if (p is Opportunity) { var weekDiffIfUsed = m.AddVar(-maxWeek, maxWeek, GRB.CONTINUOUS, "weekDiffIfUsed"); //m.Update(); var wD = weekValue - plannedWeek; m.AddConstr(weekDiffIfUsed >= wD - (1 - totalBatchesOfProject[p][0]) * maxWeek, "weekDiffConstraintDefinition1"); m.AddConstr(weekDiffIfUsed <= wD + (1 - totalBatchesOfProject[p][0]) * maxWeek, "weekDiffConstraintDefinition2"); m.AddConstr(weekDiffIfUsed <= (totalBatchesOfProject[p][0]) * maxWeek, "weekDiffConstraintDefinition3"); m.AddConstr(weekDiffIfUsed >= -(totalBatchesOfProject[p][0]) * maxWeek, "weekDiffConstraintDefinition4"); weekDiff = weekDiffIfUsed; } else { weekDiff = weekValue - plannedWeek; } m.AddConstr(varMaxedValue[pbi] >= weekDiff, "maxedWeekDiffValueConstraintDefinition"); //m.AddConstr(varMaxedValue[pbi] >= 0, "maxedWeekDiffValueConstraintDefinition"); //m.AddConstr(varMaxedValue[pbi] <= weekDiff + maxWeek * (varDecisionVar[pbi]), "maxedWeekDiffValueConstraintDefinition"); //m.AddConstr(varMaxedValue[pbi] <= 0 + maxWeek * (1 - varDecisionVar[pbi]), "maxedWeekDiffValueConstraintDefinition"); double firstBatchImportance = pbi == 0 ? 1 : 0.2; // mainly the first batch is important, the rest is meh weekValues.Add(weekValue); weekDiffs.Add(weekDiff); double revenueBase = p.Revenue == 0 ? 1E+8 : p.Revenue; // if it's an internal project it must not be shifted, therefore we make the penalty high revenueBase /= numericScale; delays.Add(varMaxedValue[pbi] * delayPenaltyMultiplier * revenueBase * firstBatchImportance); interests.Add(-(weekDiff - varMaxedValue[pbi]) * interestPenaltyMultiplier * revenueBase * firstBatchImportance); margin -= delays.Last() + interests.Last(); } // constraint: batches of a project have to be in succession, i.e. batch2 can't come after batch3 chronologically if (pbi > 0) { m.AddConstr(weekValue - previousWeekValue >= 0, "batchesOfProjectHaveToBeInSuccession"); } previousWeekValue = weekValue; } } //m.SetObjective(margin, GRB.MAXIMIZE); m.Update(); m.Write("ilproman3.mps"); m.Write("ilproman3.mst"); //m.Tune(); //m.GetTuneResult(0); m.Optimize(); //env.Set(GRB.IntParam.IISMethod, 0); // makes IIS computation fast but potentially inaccurate m.ComputeIIS(); m.Write("ilp.ilp"); // TODO: Max 5 weeks delay per project // build the solution from the optimization var sol = new Schedule(); int batchCount = 0; double cumulatedDelays = 0; double cumulatedInterests = 0; foreach (var p in scenario.Projects) { List <Schedule.BatchAllocation> allocatedBatches = new List <Schedule.BatchAllocation>(); var data = new List <double[]>(); for (int bi = 0; bi < p.Batches.Count(); bi++) { var b = p.Batches[bi]; var delay = delays[batchCount].Value; var interest = interests[batchCount].Value; cumulatedDelays += delay; cumulatedInterests += interest; var weekValue = weekValues[batchCount].Value; var weekDiff = weekDiffs[batchCount].Value; // figure out on which week and which line the batch is allocated double dayLine1 = 0; double dayLine2 = 0; if (b.Compatibility == Batch.LineCompatibility.Line1) { dayLine1 = varStartTimesBatches1[bBc + batchesLine1.IndexOf(b)].Get(GRB.DoubleAttr.X); } else if (b.Compatibility == Batch.LineCompatibility.Line2) { dayLine2 = varStartTimesBatches2[bBc + batchesLine2.IndexOf(b)].Get(GRB.DoubleAttr.X); } else { var bbi = batchesBothLines.IndexOf(b); var lineDecision = varLineDecision[bbi].Get(GRB.DoubleAttr.X); dayLine1 = varStartTimesBatches1[bbi].Get(GRB.DoubleAttr.X) * (1 - lineDecision); dayLine2 = varStartTimesBatches2[bbi].Get(GRB.DoubleAttr.X) * lineDecision; } data.Add(new double[] { delay, interest, weekValue, weekDiff, dayLine1 + dayLine2 }); if (dayLine1 > 0 && dayLine2 > 0) { throw new InvalidOperationException(); } var alloc = Schedule.LineAllocation.None; if (p is FixedProject || (p is Opportunity && totalBatchesOfProject[p][0].Value > 0.5)) { if (b.Compatibility == Batch.LineCompatibility.Both) { alloc = varLineDecision[batchesBothLines.IndexOf(b)].Get(GRB.DoubleAttr.X) > 0.5 ? Schedule.LineAllocation.Line2 : Schedule.LineAllocation.Line1; } else { alloc = b.Compatibility == Batch.LineCompatibility.Line1 ? Schedule.LineAllocation.Line1 : Schedule.LineAllocation.Line2; } } //if (dayLine1 > 0) alloc = Solution.LineAllocation.Line1; //if (dayLine2 > 0) alloc = Solution.LineAllocation.Line2; allocatedBatches.Add(new Schedule.BatchAllocation(b, alloc, earliestDate.AddDays(dayLine1 + dayLine2))); batchCount++; } sol.Add(new Schedule.ProjectAllocation(p, allocatedBatches)); } /*var maxMustWinDate = mustWinOpportunitites.Max(p => p.DeliveryDate.AddDays(7 * p.Batches.Count())).AddDays(7 * 3); * var minMustWinDate = mustWinOpportunitites.Min(p2 => p2.DeliveryDate); * var sevenmonthsrange = sol.Where(p => p.Project.DeliveryDate >= minMustWinDate && p.Project.DeliveryDate <= maxMustWinDate).ToArray(); * var ops = sevenmonthsrange.Where(p => mustWinOpportunitites.Contains(p.Project) || p.Project is FixedProject); * var s = ops.Sum(p => p.Project.Revenue);*/ return(sol); }
public Instance Match(Instance instance, string path, bool print) { try { LP = ""; if (!System.IO.Directory.Exists(path) && print) System.IO.Directory.CreateDirectory(path); GRBEnv env = new GRBEnv("mip1.log"); GRBModel model = new GRBModel(env); List<LPEdge> LPEdges = new List<LPEdge>(); if (print) { instance.Draw().Save(path + "/0Start.bmp"); } int EdgeCounter = 0; foreach (Instance.Applicant a in instance.Applicants) { EdgeCounter += a.Priorities.Count; foreach (Instance.Priority Prio in a.Priorities) { { LPEdges.Add(new LPEdge(a, instance.Posts[Prio.Target], Prio.Rank)); if (Prio.Rank == 0) instance.Posts[Prio.Target].IsF = 1; } } } // Create variables GRBVar[] Edges = new GRBVar[EdgeCounter]; for (int i = 0; i < Edges.Length; i++) { Edges[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "ve" + i.ToString()); } // Integrate new variables model.Update(); if (print) LP += "Applicant Matching Conditions:" + Environment.NewLine; foreach (Instance.Applicant a in instance.Applicants) { GRBLinExpr Temp = new GRBLinExpr(); for (int i = 0; i < LPEdges.Count; i++) { if (LPEdges[i].Applicant == a) { Temp += Edges[i]; if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") + "; } } model.AddConstr(Temp == 1.0, "a" + a.ID.ToString()); if (print) LP += " = 1;" + Environment.NewLine; } if (print) LP += Environment.NewLine + "Post Matching Conditions:" + Environment.NewLine; foreach (Instance.Post p in instance.Posts) { GRBLinExpr Temp = new GRBLinExpr(); for (int i = 0; i < LPEdges.Count; i++) { if (LPEdges[i].Post == p) { Temp += Edges[i]; if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") + "; } } model.AddConstr(Temp <= 1.0, "p" + p.ID.ToString()); if (print) LP += " <= 1;" + Environment.NewLine; } if (print) LP += Environment.NewLine + "First Choice Conditions:" + Environment.NewLine; for (int i = 0; i < LPEdges.Count; i++) { LPEdge le1 = LPEdges[i]; if (le1.Post.IsF == 1 && le1.Rank != 0) { model.AddConstr(Edges[i] <= 0, "s" + i.ToString()); if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") <= 0;" + Environment.NewLine; for (int j = 0; j < LPEdges[i].Applicant.Priorities.Count; j++) { if (LPEdges[i].Applicant.Priorities[j].Target == LPEdges[i].Post.ID && LPEdges[i].Rank == LPEdges[i].Applicant.Priorities[j].Rank) { LPEdges[i].Applicant.Priorities.RemoveAt(j); } } } } if (print) LP += Environment.NewLine + "Second Choice Conditions:" + Environment.NewLine; for (int i = 0; i < LPEdges.Count; i++) { LPEdge le1 = LPEdges[i]; foreach (LPEdge le2 in LPEdges) { if (le2 != le1 && le2.Post.IsF == 0 && le1.Applicant == le2.Applicant && le2.Rank != 0 && le2.Rank < le1.Rank) { model.AddConstr(Edges[i] <= 0, "s" + i.ToString()); if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") <= 0;" + Environment.NewLine; for (int j = 0; j < LPEdges[i].Applicant.Priorities.Count; j++) { if (LPEdges[i].Applicant.Priorities[j].Target == LPEdges[i].Post.ID && LPEdges[i].Rank == LPEdges[i].Applicant.Priorities[j].Rank) { LPEdges[i].Applicant.Priorities.RemoveAt(j); } } break; } } } if (print) LP += Environment.NewLine + "First Post Conditions:" + Environment.NewLine; foreach (Instance.Post p in instance.Posts) { if (p.IsF == 1) { GRBLinExpr Temp = new GRBLinExpr(); for (int i = 0; i < LPEdges.Count; i++) { if (LPEdges[i].Post == p) { Temp += Edges[i]; if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") + "; } } model.AddConstr(Temp >= 1.0, "f" + p.ID.ToString()); if (print) LP += ">= 1;" + Environment.NewLine; } } // Optimize model model.Optimize(); if (print) { instance.Draw().Save(path + "/1Reduced.bmp"); } for (int i = 0; i < Edges.Length; i++) { if (Edges[i].Get(GRB.DoubleAttr.X) == 1) { instance.AddMatch(LPEdges[i].Post.ID, LPEdges[i].Applicant.ID); } } if (print) { instance.Draw().Save(path + "/2Matched.bmp"); } // Dispose of model and env model.Dispose(); env.Dispose(); return instance; } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); return null; } }
static void Main(string[] args) { double[] Demand = new double[] { 15, 18, 14, 20 }; double[] Capacity = new double[] { 20, 22, 17, 19, 18 }; double[,] ShipCosts = new double[, ] { { 4000, 2500, 1200, 2200 }, { 2000, 2600, 1800, 2600 }, { 3000, 3400, 2600, 3100 }, { 2500, 3000, 4100, 3700 }, { 4500, 4000, 3000, 3200 } }; int nWarehouses = Capacity.Length; int nCustomers = Demand.Length; GRBEnv env = new GRBEnv(); GRBModel m = new GRBModel(env); GRBVar[,] Ship = new GRBVar[nWarehouses, nCustomers]; for (int i = 0; i < nWarehouses; ++i) { for (int j = 0; j < nCustomers; ++j) { Ship[i, j] = m.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "ship." + i + "." + j); } } GRBVar[] Shortage = new GRBVar[nCustomers]; for (int j = 0; j < nCustomers; ++j) { Shortage[j] = m.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "shortage." + j); } GRBVar TotalShortage = m.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "TotalShortage"); GRBVar TotalShippingCost = m.AddVar(0, GRB.INFINITY, 1, GRB.CONTINUOUS, "TotalShippingCost"); m.Update(); GRBConstr[] DemandCon = new GRBConstr[nCustomers]; for (int j = 0; j < nCustomers; ++j) { GRBLinExpr lhs = 0.0; for (int i = 0; i < nWarehouses; ++i) { lhs += Ship[i, j]; } DemandCon[j] = m.AddConstr(lhs == Demand[j] - Shortage[j], "demand." + j); } GRBConstr[] CapacityCon = new GRBConstr[nWarehouses]; for (int i = 0; i < nWarehouses; ++i) { GRBLinExpr lhs = 0.0; for (int j = 0; j < nCustomers; ++j) { lhs += Ship[i, j]; } CapacityCon[i] = m.AddConstr(lhs <= Capacity[i], "capacity." + i); } GRBLinExpr expr = 0.0; for (int j = 0; j < nCustomers; ++j) { expr += Shortage[j]; } GRBConstr TotalShortageCon = m.AddConstr(expr == TotalShortage, "total_shortage"); expr = 0.0; for (int i = 0; i < nWarehouses; ++i) { for (int j = 0; j < nCustomers; ++j) { expr += ShipCosts[i, j] * Ship[i, j]; } } GRBConstr TotalShippingCon = m.AddConstr(expr == TotalShippingCost, "total_shipping"); while (true) { m.Optimize(); double OptShortage = TotalShortage.Get(GRB.DoubleAttr.X); double OptShipping = TotalShippingCost.Get(GRB.DoubleAttr.X); Console.WriteLine("TotalShortage = {0}", OptShortage); Console.WriteLine("TotalShippingCost= {0}", OptShipping); if (OptShortage < EPS) { break; } double ObjectiveBound = TotalShortage.Get(GRB.DoubleAttr.SAObjUp); TotalShortage.Set(GRB.DoubleAttr.Obj, ((1 + EPS) * ObjectiveBound)); } }
public List <int[]> SolveVRP(int timeLimitMilliseconds) { using (var env = new GRBEnv($"{DateTime.Now:yy-MM-dd-HH-mm-ss}_vrp_gurobi.log")) using (var vrpModel = new GRBModel(env)) { #region initialize Variables var numberOfRoutes = input.Santas.Length * input.Days.Length; var v = new GRBVar[numberOfRoutes][]; // [santa] visits [visit] var w = new GRBVar[numberOfRoutes][]; // [santa] uses [way] for (int s = 0; s < numberOfRoutes; s++) { v[s] = new GRBVar[visitDurations.Length]; for (int i = 0; i < v[s].Length; i++) { v[s][i] = vrpModel.AddVar(0, 1, 0.0, GRB.BINARY, $"v[{s}][{i}]"); } w[s] = vrpModel.AddVars(distances.GetLength(0) * distances.GetLength(1), GRB.BINARY); } #endregion initialize Variables #region add constraints SelfieConstraint(vrpModel, numberOfRoutes, w); VisitVisitedOnce(vrpModel, numberOfRoutes, v); IncomingOutgoingWaysConstraints(vrpModel, numberOfRoutes, w, v); IncomingOutgoingSanta(vrpModel, numberOfRoutes, v, w); IncomingOutgoingSantaHome(vrpModel, numberOfRoutes, w, v); NumberOfWaysMatchForSanta(vrpModel, numberOfRoutes, v, w); BreakHandling(vrpModel, numberOfRoutes, v); #endregion add constraints var totalWayTime = new GRBLinExpr(0); var longestRoute = vrpModel.AddVar(0, input.Days.Max(d => d.to - d.from), 0, GRB.CONTINUOUS, "longestRoute"); for (int s = 0; s < numberOfRoutes; s++) { var routeTime = new GRBLinExpr(0); for (int i = 0; i < visitDurations.Length; i++) { routeTime += v[s][i] * visitDurations[i]; for (int j = 0; j < visitDurations.Length; j++) { routeTime += AccessW(w[s], i, j) * distances[i, j]; } } totalWayTime += routeTime; vrpModel.AddConstr(longestRoute >= routeTime, $"longesRouteConstr{s}"); } vrpModel.SetObjective( +(40d / 3600d) * totalWayTime + (30d / 3600d) * longestRoute , GRB.MINIMIZE); vrpModel.Parameters.LazyConstraints = 1; vrpModel.SetCallback(new VRPCallbackSolverCallback(w, AccessW, ConvertBack)); vrpModel.Parameters.TimeLimit = timeLimitMilliseconds / 1000; InitializeModel(w, v, numberOfRoutes, input.Visits, input.Santas.Length); vrpModel.Optimize(); if (vrpModel.SolCount == 0) { return(null); } var routes = new List <int[]>(); for (int s = 0; s < numberOfRoutes; s++) { var route = new List <int>(); var currVisit = 0; do { route.Add(currVisit); for (int i = 0; i < visitDurations.Length; i++) { if (AccessW(w[s], currVisit, i).X > 0.5) { currVisit = i; break; } } } while (currVisit != 0); routes.Add(route.ToArray()); } vrpModel.Reset(); return(routes); } }
public static Graph RunSolver(Graph graph) { GRBEnv env = new GRBEnv(); env.Set(GRB.IntParam.OutputFlag, 0); env.Set(GRB.IntParam.LogToConsole, 0); env.Set(GRB.IntParam.Presolve, 2); env.Set(GRB.DoubleParam.Heuristics, 0.0); GRBModel model = new GRBModel(env); GRBVar[] variables = new GRBVar[graph.NumberOfEdges]; model.SetCallback(new LPSolverCallback()); Dictionary<Edge, GRBVar> edgeVars = new Dictionary<Edge, GRBVar>(); // Add variables to the LP model for (int i = 0; i < graph.NumberOfEdges; i++) { variables[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "x_" + i); edgeVars.Add(graph.Edges[i], variables[i]); } model.Update(); // Add constraints to the LP model Console.Write("\rRunning LP. Creating constraints...\r"); //var nonTerminals = graph.Vertices.Except(graph.Terminals).ToList(); ulong conNr = 0; //var terminalCombinations = new List<List<Vertex>>(); // Assume, without loss of generality, that Terminals[0] is the root, and thus is always included int rootNr = 1; foreach (var rootTerminal in graph.Terminals) //var rootTerminal = graph.Terminals[0]; { Console.Write("\rRunning LP. Creating constraints... {0}/{1}\r", rootNr, graph.Terminals.Count); foreach (var combination in GetBFS(graph, rootTerminal)) { var nodes = combination.ToList(); //new HashSet<Vertex>(combination); if (nodes.Count == graph.NumberOfVertices || graph.Terminals.All(nodes.Contains)) continue; //Debug.WriteLine("Combination: {0}", string.Join(" ", nodes)); //for (int i = 1; i <= nodes.Count; i++) { var edges = nodes//.Take(i) .SelectMany(graph.GetEdgesForVertex) .Distinct() .Where(x => x.WhereOne(y => !nodes.Contains(y))); GRBLinExpr expression = 0; foreach (var edge in edges) expression.AddTerm(1, edgeVars[edge]); model.AddConstr(expression >= 1.0, "subset_" + conNr); conNr++; if (conNr % 100000 == 0) { //model = model.Presolve(); //Pre-solve the model every 1000 constraints. int constrBefore = model.GetConstrs().Length, varsBefore = model.GetVars().Length; Debug.WriteLine("Presolve called."); var presolved = model.Presolve(); Debug.WriteLine("Model has {0} constraints, {1} variables. Presolve has {2} constraints, {3} variables", constrBefore, varsBefore, presolved.GetConstrs().Length, presolved.GetVars().Length); } } } //Debug.WriteLine(" "); //Debug.WriteLine(" "); rootNr++; } //terminalCombinations.Add(new List<Vertex>(new[] { graph.Terminals[0] })); //for (int j = 1; j < graph.Terminals.Count - 1; j++) // terminalCombinations.AddRange(new Combinations<Vertex>(graph.Terminals.Skip(1), j).Select(combination => combination.Union(new[] { graph.Terminals[0] }).ToList())); //long nonTerminalSetsDone = 0; //long nonTerminalSets = 0; //for (int i = 0; i <= nonTerminals.Count; i++) // nonTerminalSets += Combinations<Vertex>.NumberOfCombinations(nonTerminals.Count, i); //for (int i = 0; i <= nonTerminals.Count; i++) //{ // foreach (var nonTerminalSet in new Combinations<Vertex>(nonTerminals, i)) // { // foreach (var nodes in (from a in terminalCombinations // select new HashSet<Vertex>(a.Union(nonTerminalSet)))) // { // var edges = nodes.SelectMany(graph.GetEdgesForVertex) // .Distinct() // .Where(x => x.WhereOne(y => !nodes.Contains(y))); // GRBLinExpr expression = 0; // foreach (var edge in edges) // expression.AddTerm(1, edgeVars[edge]); // model.AddConstr(expression >= 1.0, "subset_" + conNr); // conNr++; // } // nonTerminalSetsDone++; // if (nonTerminalSetsDone % 100 == 0) // Console.Write("\rRunning LP. Creating constraints... {0}/{1} ({2:0.000}%)\r", nonTerminalSetsDone, nonTerminalSets, nonTerminalSetsDone * 100.0 / nonTerminalSets); // } //} // Solve the LP model Console.Write("\rRunning LP. Creating objective & updating... \r"); GRBLinExpr objective = new GRBLinExpr(); for (int i = 0; i < graph.NumberOfEdges; i++) objective.AddTerm(graph.Edges[i].Cost, variables[i]); model.SetObjective(objective, GRB.MINIMIZE); Console.Write("\rRunning LP. Tuning... \r"); model.Tune(); Debug.WriteLine("Presolve called."); model.Presolve(); Console.Write("\rRunning LP. Solving... \r"); Debug.WriteLine("Optimize called."); model.Optimize(); Graph solution = graph.Clone(); HashSet<Edge> includedEdges = new HashSet<Edge>(); for (int i = 0; i < solution.NumberOfEdges; i++) { var value = variables[i].Get(GRB.DoubleAttr.X); if (value == 1) includedEdges.Add(solution.Edges[i]); } foreach (var edge in solution.Edges.ToList()) if (!includedEdges.Contains(edge)) solution.RemoveEdge(edge); Console.Write("\r \r"); return solution; }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Amount each worker is paid to work one shift double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[,] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.Set(GRB.StringAttr.ModelName, "assignment"); // Assignment variables: x[w][s] == 1 if worker w is assigned // to shift s. Since an assignment model always produces integer // solutions, we use continuous variables and solve as an LP. GRBVar[,] x = new GRBVar[nWorkers,nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w,s] = model.AddVar(0, availability[w,s], pay[w], GRB.CONTINUOUS, Workers[w] + "." + Shifts[s]); } } // The objective is to minimize the total pay costs model.Set(GRB.IntAttr.ModelSense, 1); // Update model to integrate new variables model.Update(); // Constraint: assign exactly shiftRequirements[s] workers // to each shift s for (int s = 0; s < nShifts; ++s) { GRBLinExpr lhs = 0.0; for (int w = 0; w < nWorkers; ++w) lhs += x[w, s]; model.AddConstr(lhs == shiftRequirements[s], Shifts[s]); } // Optimize model.Optimize(); int status = model.Get(GRB.IntAttr.Status); if (status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is unbounded"); return; } if (status == GRB.Status.OPTIMAL) { Console.WriteLine("The optimal objective is " + model.Get(GRB.DoubleAttr.ObjVal)); return; } if ((status != GRB.Status.INF_OR_UNBD) && (status != GRB.Status.INFEASIBLE)) { Console.WriteLine("Optimization was stopped with status " + status); return; } // Do IIS Console.WriteLine("The model is infeasible; computing IIS"); LinkedList<string> removed = new LinkedList<string>(); // Loop until we reduce to a model that can be solved while (true) { model.ComputeIIS(); Console.WriteLine("\nThe following constraint 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 removed.AddFirst(c.Get(GRB.StringAttr.ConstrName)); model.Remove(c); break; } } Console.WriteLine(); model.Optimize(); status = model.Get(GRB.IntAttr.Status); if (status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is unbounded"); return; } if (status == GRB.Status.OPTIMAL) { break; } if ((status != GRB.Status.INF_OR_UNBD) && (status != GRB.Status.INFEASIBLE)) { Console.WriteLine("Optimization was stopped with status " + status); return; } } Console.WriteLine("\nThe following constraints were removed " + "to get a feasible LP:"); foreach (string s in removed) { Console.Write(s + " "); } Console.WriteLine(); // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public void RangeSetup(GRBModel model, double lb, INumExpr expr, double ub, string name) { this.model = model; this.LB = lb; this.UB = ub; this._name = name; if (expr == null) { _expr = new INumExpr(); } else { _expr = expr; } this.constr = null; if (lb > -System.Double.MaxValue && ub < System.Double.MaxValue) { // "lb < expr < ub" --> " expr - newvar = lb, 0 < newvar < ub - lb" GRBVar var = model.AddVar(0, ub - lb, 0, GRB.CONTINUOUS, null); GRBLinExpr modExpr = Expr.expr - var; this.constr = model.AddConstr(modExpr, GRB.EQUAL, lb, name); } else if (lb > -System.Double.MaxValue) { this.constr = model.AddConstr(Expr.expr, GRB.GREATER_EQUAL, lb, name); } else { this.constr = model.AddConstr(Expr.expr, GRB.LESS_EQUAL, ub, name); } }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Amount each worker is paid to work one shift double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[, ] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.ModelName = "assignment"; // Assignment variables: x[w][s] == 1 if worker w is assigned // to shift s. Since an assignment model always produces integer // solutions, we use continuous variables and solve as an LP. GRBVar[,] x = new GRBVar[nWorkers, nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w, s] = model.AddVar(0, availability[w, s], pay[w], GRB.CONTINUOUS, Workers[w] + "." + Shifts[s]); } } // The objective is to minimize the total pay costs model.ModelSense = GRB.MINIMIZE; // Constraint: assign exactly shiftRequirements[s] workers // to each shift s for (int s = 0; s < nShifts; ++s) { GRBLinExpr lhs = 0.0; for (int w = 0; w < nWorkers; ++w) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs == shiftRequirements[s], Shifts[s]); } // Optimize model.Optimize(); int status = model.Status; if (status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is unbounded"); return; } if (status == GRB.Status.OPTIMAL) { Console.WriteLine("The optimal objective is " + model.ObjVal); return; } if ((status != GRB.Status.INF_OR_UNBD) && (status != GRB.Status.INFEASIBLE)) { Console.WriteLine("Optimization was stopped with status " + status); return; } // Relax the constraints to make the model feasible Console.WriteLine("The model is infeasible; relaxing the constraints"); int orignumvars = model.NumVars; model.FeasRelax(0, false, false, true); model.Optimize(); status = model.Status; if ((status == GRB.Status.INF_OR_UNBD) || (status == GRB.Status.INFEASIBLE) || (status == GRB.Status.UNBOUNDED)) { Console.WriteLine("The relaxed model cannot be solved " + "because it is infeasible or unbounded"); return; } if (status != GRB.Status.OPTIMAL) { Console.WriteLine("Optimization was stopped with status " + status); return; } Console.WriteLine("\nSlack values:"); GRBVar[] vars = model.GetVars(); for (int i = orignumvars; i < model.NumVars; ++i) { GRBVar sv = vars[i]; if (sv.X > 1e-6) { Console.WriteLine(sv.VarName + " = " + sv.X); } } // Dispose of model and environment model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Amount each worker is paid to work one shift double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[, ] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.Set(GRB.StringAttr.ModelName, "assignment"); // Assignment variables: x[w][s] == 1 if worker w is assigned // to shift s. Since an assignment model always produces integer // solutions, we use continuous variables and solve as an LP. GRBVar[,] x = new GRBVar[nWorkers, nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w, s] = model.AddVar(0, availability[w, s], pay[w], GRB.CONTINUOUS, Workers[w] + "." + Shifts[s]); } } // The objective is to minimize the total pay costs model.Set(GRB.IntAttr.ModelSense, 1); // Update model to integrate new variables model.Update(); // Constraint: assign exactly shiftRequirements[s] workers // to each shift s LinkedList <GRBConstr> reqCts = new LinkedList <GRBConstr>(); for (int s = 0; s < nShifts; ++s) { GRBLinExpr lhs = 0.0; for (int w = 0; w < nWorkers; ++w) { lhs.AddTerm(1.0, x[w, s]); } GRBConstr newCt = model.AddConstr(lhs == shiftRequirements[s], Shifts[s]); reqCts.AddFirst(newCt); } // Optimize model.Optimize(); int status = model.Get(GRB.IntAttr.Status); if (status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is unbounded"); return; } if (status == GRB.Status.OPTIMAL) { Console.WriteLine("The optimal objective is " + model.Get(GRB.DoubleAttr.ObjVal)); return; } if ((status != GRB.Status.INF_OR_UNBD) && (status != GRB.Status.INFEASIBLE)) { Console.WriteLine("Optimization was stopped with status " + status); return; } // Add slack variables to make the model feasible Console.WriteLine("The model is infeasible; adding slack variables"); // Set original objective coefficients to zero model.SetObjective(new GRBLinExpr()); // Add a new slack variable to each shift constraint so that the shifts // can be satisfied LinkedList <GRBVar> slacks = new LinkedList <GRBVar>(); foreach (GRBConstr c in reqCts) { GRBColumn col = new GRBColumn(); col.AddTerm(1.0, c); GRBVar newvar = model.AddVar(0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, col, c.Get(GRB.StringAttr.ConstrName) + "Slack"); slacks.AddFirst(newvar); } // Solve the model with slacks model.Optimize(); status = model.Get(GRB.IntAttr.Status); if ((status == GRB.Status.INF_OR_UNBD) || (status == GRB.Status.INFEASIBLE) || (status == GRB.Status.UNBOUNDED)) { Console.WriteLine("The model with slacks cannot be solved " + "because it is infeasible or unbounded"); return; } if (status != GRB.Status.OPTIMAL) { Console.WriteLine("Optimization was stopped with status " + status); return; } Console.WriteLine("\nSlack values:"); foreach (GRBVar sv in slacks) { if (sv.Get(GRB.DoubleAttr.X) > 1e-6) { Console.WriteLine(sv.Get(GRB.StringAttr.VarName) + " = " + sv.Get(GRB.DoubleAttr.X)); } } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public static double MIP_arc_based(int SAA_m, int SAA_type, int sample_size) { int trial_limit = sample_size; System.Console.WriteLine("Constructing the MIP with Gurobi..."); double solution = -1; try { GRBEnv env = new GRBEnv("mip1.log"); GRBModel model = new GRBModel(env); //model.Parameters.Presolve = 1; GRBVar[] y_j = new GRBVar[E]; GRBVar[,] x_ir = new GRBVar[N, sample_size]; System.Console.WriteLine("Creating y_i (edges)"); for (int i = 0; i < E; i++) { y_j[i] = model.AddVar(0.0, 1.0, 0, GRB.BINARY, "y_" + node_index[unique_arcs[i].Key.Head] + "_" + node_index[unique_arcs[i].Key.Tail]); } System.Console.WriteLine("Creating x_ir"); for (int i = 0; i < N; i++) { for (int r = 0; r < sample_size; r++) { x_ir[i, r] = model.AddVar(0.0, 1.0, 1.0, GRB.CONTINUOUS, "x_" + i + "_" + r); } } model.ModelSense = GRB.MINIMIZE; //---------------------------------------------------------- //--------------- create the constraints int counter = 0; GRBLinExpr temp_exp2; temp_exp2 = 0.0; System.Console.WriteLine("Starting the constraints... Total : " + (trial_limit * N + 1) + " constraints"); // exactly k initial active users for (int i = 0; i < E; i++) { temp_exp2.AddTerm(1.0, y_j[i]); } model.AddConstr(temp_exp2 == K, "constraint_y"); temp_exp2 = 0.0; //--- influence constraints x_i_r <= Sum_j (y_j) j in all accessing nodes to i (total of N.R constraints) //string[] neigh_arr; GRBLinExpr temp_exp; int j = 0; temp_exp = 0.0; int counter2 = 0; ReadData temp_arc = new ReadData(); for (int r = 0; r < trial_limit; r++) { for (int i = 0; i < N; i++) { //if (SAA_tree_list[r][i].Count > 0) //if (x_exist[r, i] == true) { //x_ir[i, r] = model.AddVar(0.0, 1.0, 1.0, GRB.CONTINUOUS, "x_" + i + "_" + r); temp_exp.AddTerm(1.0, x_ir[i, r]); //if (SAA_tree_list[r][i].Count <= N) { foreach (UInt16 node in SAA_pred_list[r][i]) //my predecessors can activate me { var x = unique_arcs.FindIndex(a => a.Key.Head == node_set[(int)node] && a.Key.Tail == node_set[i]); //int arcID=unique_arcs.IndexOf() temp_exp2.AddTerm(-1, x_ir[(int)node, r]); temp_exp2.AddTerm(1, y_j[x]); model.AddConstr(temp_exp + temp_exp2 >= 0, "constraint_2" + (counter + 1)); temp_exp2 = 0.0; counter++; } } } //end of if for null neighbourhood temp_exp = 0.0; } //end of for loop for nodes } //end of for loop for sample size R for (int r = 0; r < trial_limit; r++) { for (int i = 0; i < I; i++) { temp_exp.AddTerm(1.0, x_ir[(int)initial_infected[i], r]); model.AddConstr(temp_exp >= 1, "constraint_3" + (counter + 1)); temp_exp = 0.0; } } //no need for this in edge blocking //for (int i = 0; i < I; i++) //{ // temp_exp.AddTerm(1.0, y_j[(int)initial_infected[i]]); // model.AddConstr(temp_exp == 0, "constraint_3" + (counter + 1)); // temp_exp = 0.0; //} model.Write("model.lp"); //model.Write("modelGRB2" + SAA_m + ".mps"); //model.Write("modelGRB2" + SAA_m + ".lp"); GRBModel p = model.Presolve(); p.Write("presolve.lp"); model.Optimize(); if (model.Status == GRB.Status.OPTIMAL) { Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal)); solution = model.Get(GRB.DoubleAttr.ObjVal); List <UInt16> SAA_sample_result = new List <UInt16>(K); int isfractional = 0; result_set = new List <ushort>(); for (int jj = 0; jj < y_j.Count(); ++jj) { if (y_j[jj].X > 0.001) { //result_set.Add(node_set[jj]); result_set.Add(node_set[jj]); SAA_sample_result.Add((UInt16)jj); System.Console.WriteLine(y_j[jj].VarName + "=" + y_j[jj].X); if (y_j[jj].X < 0.9) { System.Console.WriteLine("Fractional value found"); System.Console.ReadKey(); isfractional = 1; } } } if (isfractional == 1) { System.Console.WriteLine("To conitnue click..."); System.Console.ReadKey(); } SAA_list.Add(SAA_sample_result); } else { Console.WriteLine("No solution"); solution = 0; } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } return(solution); }
private static GRBVar CreateLargeVasesVariable(double glazeSupply, GRBModel model) { return(model.AddVar(0.0, glazeSupply, 0.0, GRB.INTEGER, "xL")); }
public void CriarResolverModeloExato() { Ambiente = new GRBEnv(); Modelo = new GRBModel(Ambiente); Modelo.ModelSense = GRB.MINIMIZE; GRBVar[] Y = new GRBVar[NumeroItens]; GRBVar[,] X = new GRBVar[NumeroItens, NumeroItens]; //Função objetivo (1) e Conjuntos de Restrições (5) e (6) for (int j = 0; j < NumeroItens; j++) { Y[j] = Modelo.AddVar(0, 1, 0, GRB.BINARY, "y_" + j.ToString()); } for (int i = 0; i < NumeroItens; i++) { for (int j = 0; j < NumeroItens; j++) { X[i, j] = Modelo.AddVar(0, 1, Itens[i].Demanda * MatrizDistancias[i, j], GRB.BINARY, "x_" + i.ToString() + "_" + j.ToString()); } } //Restrição (2) GRBLinExpr expr = new GRBLinExpr(); //expr= //j=0: expr=1 Y[0] //j=1: expr=1 Y[0] + 1 Y[1] //... //j=19: expr=1 Y[0] + 1 Y[1] + ... + 1 Y[18] + 1 Y[19] for (int j = 0; j < NumeroItens; j++) { expr.AddTerm(1, Y[j]); } Modelo.AddConstr(expr == NumeroMedianas, "R2"); //Conjunto de Restrições (3) expr.Clear(); //expr= for (int i = 0; i < NumeroItens; i++) { expr.Clear(); for (int j = 0; j < NumeroItens; j++) { expr.AddTerm(1, X[i, j]); } Modelo.AddConstr(expr == 1, "R3" + "_" + i.ToString()); } //Conjunto de Restrições (4) for (int j = 0; j < NumeroItens; j++) { expr.Clear(); for (int i = 0; i < NumeroItens; i++) { expr.AddTerm(Itens[i].Demanda, X[i, j]); } Modelo.AddConstr(expr <= Itens[j].Capacidade * Y[j], "R4_" + j.ToString()); } //conjunto de restrições (GGG) //for (int i = 0; i < NumeroItens; i++) //{ // for (int j = 0; j < NumeroItens; j++) // { // Modelo.AddConstr(MatrizDistancias[i, j] * X[i, j] <= 300, "RGGG_" + i.ToString() + "_" + j.ToString()); // } //} //Escrever Modelo .lp Modelo.Write(@"C:\Teste\ModeloPmedianas.lp"); //Otimizar Modelo.Optimize(); DistanciaTotal = Modelo.ObjVal; //"Ler" resultado int NumeroMedianasJaDefinidas = 0; Dictionary <int, int> DicionarioMedianas = new Dictionary <int, int>(); for (int j = 0; j < NumeroItens; j++) { if (Y[j].X > 0.9) { Medianas[NumeroMedianasJaDefinidas].ItemMediana = j; Medianas[NumeroMedianasJaDefinidas].ItensAlocados = new List <int>(); Medianas[NumeroMedianasJaDefinidas].DistanciaItensMediana = 0; DicionarioMedianas.Add(j, NumeroMedianasJaDefinidas); NumeroMedianasJaDefinidas++; } } for (int i = 0; i < NumeroItens; i++) { for (int j = 0; j < NumeroItens; j++) { if (X[i, j].X > 0.9) { Itens[i].MedianaAlocada = DicionarioMedianas[j]; Medianas[DicionarioMedianas[j]].ItensAlocados.Add(i); Medianas[DicionarioMedianas[j]].DistanciaItensMediana += MatrizDistancias[i, j]; } } } }
public double Calculate(IList <Constraint> synthesizedConstraints, IList <Constraint> referenceConstraints) { // Assume benchmark restrictions indexes are bound to rows var matrix = new double[referenceConstraints.Count, synthesizedConstraints.Count]; for (var i = 0; i < matrix.GetLength(0); i++) { for (var j = 0; j < matrix.GetLength(1); j++) { matrix[i, j] = AngleBetweenVectors(referenceConstraints[i].GetAllCoefficients(), synthesizedConstraints[j].GetAllCoefficients()); } } // Assignment problem var env = new GRBEnv("angle.log"); var model = new GRBModel(env) { ModelSense = GRB.MINIMIZE, ModelName = "Mean Angle Assignment Problem" }; // Binary variable for each matrix cell var grbVars = new GRBVar[matrix.GetLength(0), matrix.GetLength(1)]; for (var i = 0; i < matrix.GetLength(0); i++) { for (var j = 0; j < matrix.GetLength(1); j++) { grbVars[i, j] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, $"b{i}.{j}"); } } var contraintCounter = 0; var objectiveExpr = new GRBLinExpr(); // First add contraints for each row for (var i = 0; i < matrix.GetLength(0); i++) { var rowExpr = new GRBLinExpr(); for (var j = 0; j < matrix.GetLength(1); j++) { rowExpr.AddTerm(1.0, grbVars[i, j]); // Creating objective equation ONLY ONCE ! objectiveExpr.AddTerm(matrix[i, j], grbVars[i, j]); } model.AddConstr(rowExpr, GRB.GREATER_EQUAL, 1, $"c{contraintCounter++}"); } // Transpose matrix so we can perform the same operation matrix = matrix.Transpose(); // Add contstaints for originally columns for (var i = 0; i < matrix.GetLength(0); i++) { var rowExpr = new GRBLinExpr(); for (var j = 0; j < matrix.GetLength(1); j++) { // Inverted indexes i and j rowExpr.AddTerm(1.0, grbVars[j, i]); } model.AddConstr(rowExpr, GRB.GREATER_EQUAL, 1, $"c{contraintCounter++}"); } model.SetObjective(objectiveExpr); model.Optimize(); // Back to orignal shape matrix = matrix.Transpose(); // Gets indicators for each bianry variable for solution var binarySolutions = new double[matrix.GetLength(0), matrix.GetLength(1)]; for (var i = 0; i < matrix.GetLength(0); i++) { for (var j = 0; j < matrix.GetLength(1); j++) { binarySolutions[i, j] = grbVars[i, j].X; } } // Multiplies binary indicators with coeficients var sum = Matrix.ElementwiseMultiply(matrix, binarySolutions).Sum(); model.Write("angle_out.lp"); model.Dispose(); env.Dispose(); // Return mean angle return(sum / (matrix.GetLength(0) > matrix.GetLength(1) ? matrix.GetLength(0) : matrix.GetLength(1))); }
static void Main() { try { // Nutrition guidelines, based on // USDA Dietary Guidelines for Americans, 2005 // http://www.health.gov/DietaryGuidelines/dga2005/ string[] Categories = new string[] { "calories", "protein", "fat", "sodium" }; int nCategories = Categories.Length; double[] minNutrition = new double[] { 1800, 91, 0, 0 }; double[] maxNutrition = new double[] { 2200, GRB.INFINITY, 65, 1779 }; // Set of foods string[] Foods = new string[] { "hamburger", "chicken", "hot dog", "fries", "macaroni", "pizza", "salad", "milk", "ice cream" }; int nFoods = Foods.Length; double[] cost = new double[] { 2.49, 2.89, 1.50, 1.89, 2.09, 1.99, 2.49, 0.89, 1.59 }; // Nutrition values for the foods double[,] nutritionValues = new double[,] { { 410, 24, 26, 730 }, // hamburger { 420, 32, 10, 1190 }, // chicken { 560, 20, 32, 1800 }, // hot dog { 380, 4, 19, 270 }, // fries { 320, 12, 10, 930 }, // macaroni { 320, 15, 12, 820 }, // pizza { 320, 31, 12, 1230 }, // salad { 100, 8, 2.5, 125 }, // milk { 330, 8, 10, 180 } // ice cream }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.Set(GRB.StringAttr.ModelName, "diet"); // Create decision variables for the nutrition information, // which we limit via bounds GRBVar[] nutrition = new GRBVar[nCategories]; for (int i = 0; i < nCategories; ++i) { nutrition[i] = model.AddVar(minNutrition[i], maxNutrition[i], 0, GRB.CONTINUOUS, Categories[i]); } // Create decision variables for the foods to buy GRBVar[] buy = new GRBVar[nFoods]; for (int j = 0; j < nFoods; ++j) { buy[j] = model.AddVar(0, GRB.INFINITY, cost[j], GRB.CONTINUOUS, Foods[j]); } // The objective is to minimize the costs model.Set(GRB.IntAttr.ModelSense, 1); // Update model to integrate new variables model.Update(); // Nutrition constraints for (int i = 0; i < nCategories; ++i) { GRBLinExpr ntot = 0.0; for (int j = 0; j < nFoods; ++j) ntot += nutritionValues[j,i] * buy[j]; model.AddConstr(ntot == nutrition[i], Categories[i]); } // Solve model.Optimize(); PrintSolution(model, buy, nutrition); Console.WriteLine("\nAdding constraint: at most 6 servings of dairy"); model.AddConstr(buy[7] + buy[8] <= 6.0, "limit_dairy"); // Solve model.Optimize(); PrintSolution(model, buy, nutrition); // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
private GRBLinExpr AttachedToSpecialQuestion(int y, int x, int type, Crossword crossword, GRBModel m, int sizeX, int sizeY, int maxWordLength, GRBVar[,] fields, GRBLinExpr[,] specialQuestionUsed, GRBVar[,,] specialQuestionType) { // 0 = Down, then right // 1 = Left, then down // 2 = Right, then down // 3 = Up, then right if (type == 0 && y - 1 < 0) { return(null); } if (type == 1 && x + 1 >= sizeX) { return(null); } if (type == 2 && x - 1 < 0) { return(null); } if (type == 3 && y + 1 >= sizeY) { return(null); } // Is this field attached to a special question? var attachedToSpecialQuestion = new GRBLinExpr(); for (int len = 0; len < maxWordLength; len++) { var qpos = new { y = y + (type == 0 ? -1 : 1), x = x - len }; if (type == 1 || type == 2) { qpos = new { y = y - len, x = x + (type == 1 ? 1 : -1) } } ; if ((type == 0 || type == 3) && (x - len < 0 || crossword.HasBlock(y, x - len, y, x) || crossword.HasBlock(qpos.y, qpos.x))) { continue; } if ((type == 1 || type == 2) && (y - len < 0 || crossword.HasBlock(y - len, x, y, x) || crossword.HasBlock(qpos.y, qpos.x))) { continue; } if ((object)specialQuestionUsed[qpos.y, qpos.x] == null) { continue; } var atsp = m.AddVar(0, 1, 0, GRB.BINARY, "attachedToSpecialQuestion" + type + "len" + len + "_" + y + "_" + x); var questionsInbetween = (type == 0 || type == 3) ? fields.SumRange(y, x - len, y, x) : fields.SumRange(y - len, x, y, x); m.AddConstr(atsp >= fields[qpos.y, qpos.x] + specialQuestionType[qpos.y, qpos.x, type] - 1 - questionsInbetween, "attachedToSpecialQuestion_len" + len + "_" + y + "_" + x); if (type == 0 || type == 3) { for (int xi = x - len; xi <= x; xi++) { m.AddConstr(atsp <= 1 - fields[y, xi], "notAttachedToSpecialQuestion1_len" + len + "_" + y + "_" + x); } } else { for (int yi = y - len; yi <= y; yi++) { m.AddConstr(atsp <= 1 - fields[yi, x], "notAttachedToSpecialQuestion1_len" + len + "_" + y + "_" + x); } } m.AddConstr(atsp <= fields[qpos.y, qpos.x], "notAttachedToSpecialQuestion2_len" + len + "_" + y + "_" + x); m.AddConstr(atsp <= specialQuestionType[qpos.y, qpos.x, type], "notAttachedToSpecialQuestion3_len" + len + "_" + y + "_" + x); attachedToSpecialQuestion += atsp; } return(attachedToSpecialQuestion); } }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu", "Tobi" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[, ] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Create environment GRBEnv env = new GRBEnv(); // Create initial model GRBModel model = new GRBModel(env); model.ModelName = "workforce5_cs"; // Initialize assignment decision variables: // x[w][s] == 1 if worker w is assigned to shift s. // This is no longer a pure assignment model, so we must // use binary variables. GRBVar[,] x = new GRBVar[nWorkers, nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w, s] = model.AddVar(0, availability[w, s], 0, GRB.BINARY, string.Format("{0}.{1}", Workers[w], Shifts[s])); } } // Slack variables for each shift constraint so that the shifts can // be satisfied GRBVar[] slacks = new GRBVar[nShifts]; for (int s = 0; s < nShifts; ++s) { slacks[s] = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, string.Format("{0}Slack", Shifts[s])); } // Variable to represent the total slack GRBVar totSlack = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "totSlack"); // Variables to count the total shifts worked by each worker GRBVar[] totShifts = new GRBVar[nWorkers]; for (int w = 0; w < nWorkers; ++w) { totShifts[w] = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, string.Format("{0}TotShifts", Workers[w])); } GRBLinExpr lhs; // Constraint: assign exactly shiftRequirements[s] workers // to each shift s, plus the slack for (int s = 0; s < nShifts; ++s) { lhs = new GRBLinExpr(); lhs.AddTerm(1.0, slacks[s]); for (int w = 0; w < nWorkers; ++w) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs, GRB.EQUAL, shiftRequirements[s], Shifts[s]); } // Constraint: set totSlack equal to the total slack lhs = new GRBLinExpr(); lhs.AddTerm(-1.0, totSlack); for (int s = 0; s < nShifts; ++s) { lhs.AddTerm(1.0, slacks[s]); } model.AddConstr(lhs, GRB.EQUAL, 0, "totSlack"); // Constraint: compute the total number of shifts for each worker for (int w = 0; w < nWorkers; ++w) { lhs = new GRBLinExpr(); lhs.AddTerm(-1.0, totShifts[w]); for (int s = 0; s < nShifts; ++s) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs, GRB.EQUAL, 0, string.Format("totShifts{0}", Workers[w])); } // Constraint: set minShift/maxShift variable to less <=/>= to the // number of shifts among all workers GRBVar minShift = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "minShift"); GRBVar maxShift = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "maxShift"); model.AddGenConstrMin(minShift, totShifts, GRB.INFINITY, "minShift"); model.AddGenConstrMax(maxShift, totShifts, -GRB.INFINITY, "maxShift"); // Set global sense for ALL objectives model.ModelSense = GRB.MINIMIZE; // Set primary objective model.SetObjectiveN(totSlack, 0, 2, 1.0, 2.0, 0.1, "TotalSlack"); // Set secondary objective model.SetObjectiveN(maxShift - minShift, 1, 1, 1.0, 0, 0, "Fairness"); // Save problem model.Write("workforce5_cs.lp"); // Optimize int status = solveAndPrint(model, totSlack, nWorkers, Workers, totShifts); if (status != GRB.Status.OPTIMAL) { return; } // Dispose of model and environment model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: {0}. {1}", e.ErrorCode, e.Message); } }
public GRBVar AddToModel(GRBModel model) { return(model.AddVar(lowerBound, upperBound, ObjectiveCoefficient, variableType, name)); }
/// <summary> /// Creates and saves model to a path set in <see cref="GlobalVariables.GurobiModelPath"/> /// </summary> public void Create() { using (var sr = new StreamReader(_path)) { while (!sr.EndOfStream) { Rules.Add(new Rule(sr.ReadLine())); } } // Item1 contains a list of unique Constraints and Item2 is a number of bool variables var tuple = Rules.ReturnUniqueSplitsWithBooleans(); UniqueConstraints = tuple.Item1; var inputs = new string[GlobalVariables.Dimensions]; for (var i = 0; i < GlobalVariables.Dimensions; i++) { inputs[i] = "x" + i; } // Create Gurobi Environment and model var env = new GRBEnv(); Model = new GRBModel(env) { ModelName = "OneClassClassifier" }; // Add continous variables var continousVariables = new GRBVar[inputs.Length]; for (var i = 0; i < continousVariables.Length; i++) { continousVariables[i] = Model.AddVar(-Gurobi.GRB.INFINITY, Gurobi.GRB.INFINITY, 0, Gurobi.GRB.CONTINUOUS, inputs[i]); } // Add binary variables var binaryVariables = new GRBVar[tuple.Item2]; for (var i = 0; i < binaryVariables.Length; i++) { binaryVariables[i] = Model.AddVar(0.0, 1.0, 0.0, Gurobi.GRB.BINARY, $"b{i}"); } var constraintCounter = 0; var termsCounter = 0; // Because there is always 1 dimension variable // Add constraints foreach (var constraint in UniqueConstraints) { termsCounter += 1; var valueEquals = constraint.Value; var expr = new GRBLinExpr(); expr.AddTerm(1.0, continousVariables[constraint.Axis]); foreach (var split in constraint.Splits) { double m; if (constraint.Sign == split.OriginalSign) { m = split.OriginalSign == Gurobi.GRB.LESS_EQUAL ? GlobalVariables.M : -GlobalVariables.M; } else { m = split.OriginalSign == Gurobi.GRB.LESS_EQUAL ? -GlobalVariables.M : GlobalVariables.M; } if (split.OneMinus) { valueEquals += m; termsCounter += 2; } else { m = -m; termsCounter++; } expr.AddTerm(m, binaryVariables[split.SplitNumber]); } Model.AddConstr(expr, constraint.Sign, valueEquals, $"c{constraintCounter++}"); } Constraints = constraintCounter; Terms = termsCounter; Model.Write(GlobalVariables.GurobiModelPath); }
public void BalanceGurobi() { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); DateTime CalculationTimeStart; DateTime CalculationTimeFinish; double[] results = new double[measuredValues.ToArray().Length]; if (inputData.balanceSettings.balanceSettingsConstraints == BalanceSettings.BalanceSettingsConstraints.TECHNOLOGIC) { //Create variables GRBVar[] varsTechnologic = new GRBVar[measuredValues.ToArray().Length]; for (int i = 0; i < varsTechnologic.Length; i++) { varsTechnologic[i] = model.AddVar(technologicRangeLowerBound[i], technologicRangeUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i); } //Set objective GRBQuadExpr objTechnologic = new GRBQuadExpr(); for (int i = 0; i < varsTechnologic.Length; i++) { objTechnologic.AddTerm(H[i, i] / 2.0, varsTechnologic[i], varsTechnologic[i]); } for (int i = 0; i < varsTechnologic.Length; i++) { objTechnologic.AddTerm(dVector[i], varsTechnologic[i]); } model.SetObjective(objTechnologic); //Add constraints GRBLinExpr expr; for (int i = 0; i < incidenceMatrix.RowCount; i++) { expr = new GRBLinExpr(); for (int j = 0; j < incidenceMatrix.ColumnCount; j++) { expr.AddTerm(incidenceMatrix[i, j], varsTechnologic[j]); } model.AddConstr(expr, GRB.EQUAL, 0.0, "c" + i); } // Optimize model CalculationTimeStart = DateTime.Now; model.Optimize(); CalculationTimeFinish = DateTime.Now; results = new double[varsTechnologic.Length]; for (int i = 0; i < results.Length; i++) { results[i] = varsTechnologic[i].Get(GRB.DoubleAttr.X); } } else { //Create variables GRBVar[] varsMetrologic = new GRBVar[measuredValues.ToArray().Length]; for (int i = 0; i < varsMetrologic.Length; i++) { if (measureIndicator[i, i] == 0) { varsMetrologic[i] = model.AddVar(technologicRangeLowerBound[i], technologicRangeUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i); } else { varsMetrologic[i] = model.AddVar(metrologicRangeLowerBound[i], metrologicRangeUpperBound[i], 0.0, GRB.CONTINUOUS, "x" + i); } } //Set objective GRBQuadExpr objMetroologic = new GRBQuadExpr(); for (int i = 0; i < varsMetrologic.Length; i++) { objMetroologic.AddTerm(H[i, i] / 2.0, varsMetrologic[i], varsMetrologic[i]); } for (int i = 0; i < varsMetrologic.Length; i++) { objMetroologic.AddTerm(dVector[i], varsMetrologic[i]); } model.SetObjective(objMetroologic); //Add constraints GRBLinExpr expr; for (int i = 0; i < incidenceMatrix.RowCount; i++) { expr = new GRBLinExpr(); for (int j = 0; j < incidenceMatrix.ColumnCount; j++) { expr.AddTerm(incidenceMatrix[i, j], varsMetrologic[j]); } model.AddConstr(expr, GRB.EQUAL, 0.0, "c" + i); } // Optimize model CalculationTimeStart = DateTime.Now; model.Optimize(); CalculationTimeFinish = DateTime.Now; results = new double[varsMetrologic.Length]; for (int i = 0; i < results.Length; i++) { results[i] = varsMetrologic[i].Get(GRB.DoubleAttr.X); } } model.Dispose(); env.Dispose(); double disbalanceOriginal = incidenceMatrix.Multiply(measuredValues).Subtract(reconciledValues).ToArray().Euclidean(); double disbalance = incidenceMatrix.Multiply(SparseVector.OfVector(new DenseVector(results))).Subtract(reconciledValues).ToArray().Euclidean(); balanceOutput = new BalanceOutput(); balanceOutputVariables = new List <OutputVariables>(); for (int i = 0; i < results.Length; i++) { InputVariables outputVariable = inputData.BalanceInputVariables[i]; balanceOutputVariables.Add(new OutputVariables() { id = outputVariable.id, name = outputVariable.name, value = results[i], source = outputVariable.sourceId, target = outputVariable.destinationId, upperBound = (inputData.balanceSettings.balanceSettingsConstraints == 0 || measureIndicator[i, i] == 0.0) ? technologicRangeUpperBound[i] : metrologicRangeUpperBound[i], lowerBound = (inputData.balanceSettings.balanceSettingsConstraints == 0 || measureIndicator[i, i] == 0.0) ? technologicRangeLowerBound[i] : metrologicRangeLowerBound[i] }); } balanceOutput.CalculationTime = (CalculationTimeFinish - CalculationTimeStart).TotalSeconds; balanceOutput.balanceOutputVariables = balanceOutputVariables; balanceOutput.DisbalanceOriginal = disbalanceOriginal; balanceOutput.Disbalance = disbalance; balanceOutput.GlobaltestValue = 0.0; balanceOutput.Status = "Success"; }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Amount each worker is paid to work one shift double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[, ] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.ModelName = "assignment"; // Assignment variables: x[w][s] == 1 if worker w is assigned // to shift s. Since an assignment model always produces integer // solutions, we use continuous variables and solve as an LP. GRBVar[,] x = new GRBVar[nWorkers, nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w, s] = model.AddVar(0, availability[w, s], pay[w], GRB.CONTINUOUS, Workers[w] + "." + Shifts[s]); } } // The objective is to minimize the total pay costs model.ModelSense = GRB.MINIMIZE; // Constraint: assign exactly shiftRequirements[s] workers // to each shift s for (int s = 0; s < nShifts; ++s) { GRBLinExpr lhs = 0.0; for (int w = 0; w < nWorkers; ++w) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs == shiftRequirements[s], Shifts[s]); } // Optimize model.Optimize(); int status = model.Status; if (status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is unbounded"); return; } if (status == GRB.Status.OPTIMAL) { Console.WriteLine("The optimal objective is " + model.ObjVal); return; } if ((status != GRB.Status.INF_OR_UNBD) && (status != GRB.Status.INFEASIBLE)) { Console.WriteLine("Optimization was stopped with status " + status); return; } // Do IIS Console.WriteLine("The model is infeasible; computing IIS"); LinkedList <string> removed = new LinkedList <string>(); // Loop until we reduce to a model that can be solved while (true) { model.ComputeIIS(); Console.WriteLine("\nThe following constraint cannot be satisfied:"); foreach (GRBConstr c in model.GetConstrs()) { if (c.IISConstr == 1) { Console.WriteLine(c.ConstrName); // Remove a single constraint from the model removed.AddFirst(c.ConstrName); model.Remove(c); break; } } Console.WriteLine(); model.Optimize(); status = model.Status; if (status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is unbounded"); return; } if (status == GRB.Status.OPTIMAL) { break; } if ((status != GRB.Status.INF_OR_UNBD) && (status != GRB.Status.INFEASIBLE)) { Console.WriteLine("Optimization was stopped with status " + status); return; } } Console.WriteLine("\nThe following constraints were removed " + "to get a feasible LP:"); foreach (string s in removed) { Console.Write(s + " "); } Console.WriteLine(); // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { // Nutrition guidelines, based on // USDA Dietary Guidelines for Americans, 2005 // http://www.health.gov/DietaryGuidelines/dga2005/ string[] Categories = new string[] { "calories", "protein", "fat", "sodium" }; int nCategories = Categories.Length; double[] minNutrition = new double[] { 1800, 91, 0, 0 }; double[] maxNutrition = new double[] { 2200, GRB.INFINITY, 65, 1779 }; // Set of foods string[] Foods = new string[] { "hamburger", "chicken", "hot dog", "fries", "macaroni", "pizza", "salad", "milk", "ice cream" }; int nFoods = Foods.Length; double[] cost = new double[] { 2.49, 2.89, 1.50, 1.89, 2.09, 1.99, 2.49, 0.89, 1.59 }; // Nutrition values for the foods double[,] nutritionValues = new double[, ] { { 410, 24, 26, 730 }, // hamburger { 420, 32, 10, 1190 }, // chicken { 560, 20, 32, 1800 }, // hot dog { 380, 4, 19, 270 }, // fries { 320, 12, 10, 930 }, // macaroni { 320, 15, 12, 820 }, // pizza { 320, 31, 12, 1230 }, // salad { 100, 8, 2.5, 125 }, // milk { 330, 8, 10, 180 } // ice cream }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.ModelName = "diet"; // Create decision variables for the nutrition information, // which we limit via bounds GRBVar[] nutrition = new GRBVar[nCategories]; for (int i = 0; i < nCategories; ++i) { nutrition[i] = model.AddVar(minNutrition[i], maxNutrition[i], 0, GRB.CONTINUOUS, Categories[i]); } // Create decision variables for the foods to buy GRBVar[] buy = new GRBVar[nFoods]; for (int j = 0; j < nFoods; ++j) { buy[j] = model.AddVar(0, GRB.INFINITY, cost[j], GRB.CONTINUOUS, Foods[j]); } // The objective is to minimize the costs model.ModelSense = GRB.MINIMIZE; // Nutrition constraints for (int i = 0; i < nCategories; ++i) { GRBLinExpr ntot = 0.0; for (int j = 0; j < nFoods; ++j) { ntot.AddTerm(nutritionValues[j, i], buy[j]); } model.AddConstr(ntot == nutrition[i], Categories[i]); } // Solve model.Optimize(); PrintSolution(model, buy, nutrition); Console.WriteLine("\nAdding constraint: at most 6 servings of dairy"); model.AddConstr(buy[7] + buy[8] <= 6.0, "limit_dairy"); // Solve model.Optimize(); PrintSolution(model, buy, nutrition); // Dispose of model and env 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; double maxFixed = -GRB.INFINITY; double minFixed = GRB.INFINITY; for (int p = 0; p < nPlants; ++p) { if (FixedCosts[p] > maxFixed) { maxFixed = FixedCosts[p]; } if (FixedCosts[p] < minFixed) { minFixed = FixedCosts[p]; } } // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.ModelName = "multiscenario"; // 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.ModelSense = GRB.MINIMIZE; // 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 GRBConstr[] demandConstr = new GRBConstr[nWarehouses]; 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]); } demandConstr[w] = model.AddConstr(dtot == Demand[w], "Demand" + w); } // We constructed the base model, now we add 7 scenarios // // Scenario 0: Represents the base model, hence, no manipulations. // Scenario 1: Manipulate the warehouses demands slightly (constraint right // hand sides). // Scenario 2: Double the warehouses demands (constraint right hand sides). // Scenario 3: Manipulate the plant fixed costs (objective coefficients). // Scenario 4: Manipulate the warehouses demands and fixed costs. // Scenario 5: Force the plant with the largest fixed cost to stay open // (variable bounds). // Scenario 6: Force the plant with the smallest fixed cost to be closed // (variable bounds). model.NumScenarios = 7; // Scenario 0: Base model, hence, nothing to do except giving the // scenario a name model.Parameters.ScenarioNumber = 0; model.ScenNName = "Base model"; // Scenario 1: Increase the warehouse demands by 10% model.Parameters.ScenarioNumber = 1; model.ScenNName = "Increased warehouse demands"; for (int w = 0; w < nWarehouses; w++) { demandConstr[w].ScenNRHS = Demand[w] * 1.1; } // Scenario 2: Double the warehouse demands model.Parameters.ScenarioNumber = 2; model.ScenNName = "Double the warehouse demands"; for (int w = 0; w < nWarehouses; w++) { demandConstr[w].ScenNRHS = Demand[w] * 2.0; } // Scenario 3: Decrease the plant fixed costs by 5% model.Parameters.ScenarioNumber = 3; model.ScenNName = "Decreased plant fixed costs"; for (int p = 0; p < nPlants; p++) { open[p].ScenNObj = FixedCosts[p] * 0.95; } // Scenario 4: Combine scenario 1 and scenario 3 */ model.Parameters.ScenarioNumber = 4; model.ScenNName = "Increased warehouse demands and decreased plant fixed costs"; for (int w = 0; w < nWarehouses; w++) { demandConstr[w].ScenNRHS = Demand[w] * 1.1; } for (int p = 0; p < nPlants; p++) { open[p].ScenNObj = FixedCosts[p] * 0.95; } // Scenario 5: Force the plant with the largest fixed cost to stay // open model.Parameters.ScenarioNumber = 5; model.ScenNName = "Force plant with largest fixed cost to stay open"; for (int p = 0; p < nPlants; p++) { if (FixedCosts[p] == maxFixed) { open[p].ScenNLB = 1.0; break; } } // Scenario 6: Force the plant with the smallest fixed cost to be // closed model.Parameters.ScenarioNumber = 6; model.ScenNName = "Force plant with smallest fixed cost to be closed"; for (int p = 0; p < nPlants; p++) { if (FixedCosts[p] == minFixed) { open[p].ScenNUB = 0.0; break; } } // 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].Start = 1.0; } // Now close the plant with the highest fixed cost Console.WriteLine("Initial guess:"); for (int p = 0; p < nPlants; ++p) { if (FixedCosts[p] == maxFixed) { open[p].Start = 0.0; Console.WriteLine("Closing plant " + p + "\n"); break; } } // Use barrier to solve root relaxation model.Parameters.Method = GRB.METHOD_BARRIER; // Solve multi-scenario model model.Optimize(); int nScenarios = model.NumScenarios; for (int s = 0; s < nScenarios; s++) { int modelSense = GRB.MINIMIZE; // Set the scenario number to query the information for this scenario model.Parameters.ScenarioNumber = s; // collect result for the scenario double scenNObjBound = model.ScenNObjBound; double scenNObjVal = model.ScenNObjVal; Console.WriteLine("\n\n------ Scenario " + s + " (" + model.ScenNName + ")"); // Check if we found a feasible solution for this scenario if (scenNObjVal >= modelSense * GRB.INFINITY) { if (scenNObjBound >= modelSense * GRB.INFINITY) { // Scenario was proven to be infeasible Console.WriteLine("\nINFEASIBLE"); } else { // We did not find any feasible solution - should not happen in // this case, because we did not set any limit (like a time // limit) on the optimization process Console.WriteLine("\nNO SOLUTION"); } } else { Console.WriteLine("\nTOTAL COSTS: " + scenNObjVal); Console.WriteLine("SOLUTION:"); for (int p = 0; p < nPlants; p++) { double scenNX = open[p].ScenNX; if (scenNX > 0.5) { Console.WriteLine("Plant " + p + " open"); for (int w = 0; w < nWarehouses; w++) { scenNX = transport[w, p].ScenNX; if (scenNX > 0.0001) { Console.WriteLine(" Transport " + scenNX + " units to warehouse " + w); } } } else { Console.WriteLine("Plant " + p + " closed!"); } } } } // Print a summary table: for each scenario we add a single summary // line Console.WriteLine("\n\nSummary: Closed plants depending on scenario\n"); Console.WriteLine("{0,8} | {1,17} {2,13}", "", "Plant", "|"); Console.Write("{0,8} |", "Scenario"); for (int p = 0; p < nPlants; p++) { Console.Write("{0,6}", p); } Console.WriteLine(" | {0,6} Name", "Costs"); for (int s = 0; s < nScenarios; s++) { int modelSense = GRB.MINIMIZE; // Set the scenario number to query the information for this scenario model.Parameters.ScenarioNumber = s; // Collect result for the scenario double scenNObjBound = model.ScenNObjBound; double scenNObjVal = model.ScenNObjVal; Console.Write("{0,-8} |", s); // Check if we found a feasible solution for this scenario if (scenNObjVal >= modelSense * GRB.INFINITY) { if (scenNObjBound >= modelSense * GRB.INFINITY) { // Scenario was proven to be infeasible Console.WriteLine(" {0,-30}| {1,6} " + model.ScenNName, "infeasible", "-"); } else { // We did not find any feasible solution - should not happen in // this case, because we did not set any limit (like a time // limit) on the optimization process Console.WriteLine(" {0,-30}| {1,6} " + model.ScenNName, "no solution found", "-"); } } else { for (int p = 0; p < nPlants; p++) { double scenNX = open[p].ScenNX; if (scenNX > 0.5) { Console.Write("{0,6}", " "); } else { Console.Write("{0,6}", "x"); } } Console.WriteLine(" | {0,6} " + model.ScenNName, scenNObjVal); } } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
/// <summary> /// Method called when a process token executes the step. /// </summary> public ExitType Execute(IStepExecutionContext context) { IState _timenow = _propTimenow.GetState(context); double timenow = Convert.ToDouble(_timenow.StateValue); SerializarElement sr = new SerializarElement(); if (File.Exists(sr.SerializationFile)) { Vect v = sr.deserializa(); vectores = sr.deserializa(); vectores.MipYc = v.MipYc; vectores.MipYv = v.MipYv; vectores.MipTc = v.MipTc; vectores.MipTv = v.MipTv; //Dinamico vectores.Din1 = v.Din1; vectores.DesCam = v.DesCam; vectores.Fila = v.Fila; //LP vectores.TCV = v.TCV; vectores.TCC = v.TCC; vectores.TCj = v.TCj; vectores.TDi = v.TDi; vectores.Destij = v.Destij; vectores.Dj = v.Dj; vectores.Uj = v.Uj; vectores.Ui = v.Ui; vectores.RLi = v.RLi; vectores.RUi = v.RUi; vectores.PlYc = v.PlYc; vectores.PlYv = v.PlYv; vectores.PlTc = v.PlTc; vectores.PlTv = v.PlTv; vectores.PlTcmalo = v.PlTcmalo; vectores.Mine = v.Mine; vectores.Mineralocado = v.Mineralocado; vectores.Lastrealocado = v.Lastrealocado; } int i = 30; int j = 20; double TA; TA = 0.0158333333; //tiempo de aculatado double expr; expr = 0; //variable auxiliar GRBEnv env = new GRBEnv(); GRBModel disp = new GRBModel(env); GRBLinExpr L = 320; //Numero auxiliar de velocidad de descarga GRBLinExpr M = 110; //Numero max camiones double[,] Tcvij = new double[30, 20]; double[,] Tccij = new double[30, 20]; for (int a = 0; a < i; a = a + 1) // saca tiempo de viaje total { for (int b = 0; b < j; b = b + 1) { Tcvij[a, b] = vectores.TCV[a, b] + vectores.TDi[a]; if (vectores.Destij[a, b] != 0) { Tccij[a, b] = vectores.TCC[a, b] + vectores.TCj[b] + TA; } else { Tccij[a, b] = 9999; } } } for (int b = 0; b < j; b = b + 1) { expr = 0; for (int a = 0; a < i; a = a + 1) { expr = expr + vectores.Destij[a, b]; } if (expr == 0) { vectores.Uj[b] = 0; } } GRBVar[,] Ycij = new GRBVar[30, 20]; //Camiones cargados de i a j GRBVar[,] Yvij = new GRBVar[30, 20]; //Camiones vacios de i a j GRBVar[,] Tcij = new GRBVar[30, 20]; //Throughtput cargado de i a j GRBVar[,] Tvij = new GRBVar[30, 20]; //Throughtput vacio de i a j for (int a = 0; a < i; a = a + 1) { for (int b = 0; b < j; b = b + 1) { Ycij[a, b] = disp.AddVar(0.0, 1000, 0.0, GRB.CONTINUOUS, "Yc" + a + "_" + b); Yvij[a, b] = disp.AddVar(0.0, 1000, 0.0, GRB.CONTINUOUS, "Yv" + a + "_" + b); Tcij[a, b] = disp.AddVar(0.0, 100000, 0.0, GRB.CONTINUOUS, "Tc" + a + "_" + b); //tonelaje cargado pasando hacia j en toneladas Tvij[a, b] = disp.AddVar(0.0, 100000, 0.0, GRB.CONTINUOUS, "Tv" + a + "_" + b); //tonelaje vacio pasando hacia j en toneladas } } for (int a = 0; a < i; a = a + 1) { for (int b = 0; b < j; b = b + 1) { disp.AddConstr(Tcij[a, b] == ((Ycij[a, b] / Tccij[a, b]) * L), "tonelaje_minimo" + a); disp.AddConstr(Tvij[a, b] == ((Yvij[a, b] / Tcvij[a, b]) * L), "tonelaje_maximo" + b); } } for (int b = 0; b < j; b = b + 1) { GRBLinExpr P = 0; for (int a = 0; a < i; a = a + 1) { P = P + Tcij[a, b]; } disp.AddConstr((vectores.Dj[b] * vectores.Uj[b]), GRB.LESS_EQUAL, P, "tonelaje_minimo_de_palas" + b); } for (int a = 0; a < i; a = a + 1) { GRBLinExpr P = 0; for (int b = 0; b < j; b = b + 1) { P = P + Tcij[a, b]; } disp.AddConstr(P, GRB.LESS_EQUAL, vectores.RUi[a] * vectores.Ui[a], "tonelaje_minimo_a_basureros" + a); } //Restriccion del chancador independiente for (int a = 1; a < i; a = a + 1) { GRBLinExpr P = 0; for (int b = 0; b < j; b = b + 1) { P = P + Tcij[a, b]; } disp.AddConstr(vectores.RLi[a] * vectores.Ui[a], GRB.LESS_EQUAL, P, "tonelajecargado2" + a); } for (int a = 0; a < i; a = a + 1) { GRBLinExpr P = 0; for (int b = 0; b < j; b = b + 1) { P = P + Tcij[a, b]; } disp.AddConstr(vectores.Ui[a] * (vectores.RLi[a] - (vectores.PlTcmalo[0, 3] * (1 - vectores.Uj[3]) + vectores.PlTcmalo[0, 4] * (1 - vectores.Uj[4]) + vectores.PlTcmalo[0, 5] * (1 - vectores.Uj[5]) + vectores.PlTcmalo[0, 16] * (1 - vectores.Uj[16]) + vectores.PlTcmalo[0, 17] * (1 - vectores.Uj[17]))), GRB.LESS_EQUAL, P, "tonelajecargado2" + a); } GRBLinExpr Qonda = 0; for (int a = 0; a < i; a = a + 1) { for (int b = 0; b < j; b = b + 1) { Qonda = (Qonda + Ycij[a, b] + Yvij[a, b]); } } disp.AddConstr(Qonda, GRB.LESS_EQUAL, M, "maximocamiones"); for (int b = 0; b < j; b = b + 1) { GRBLinExpr P1 = 0; GRBLinExpr P2 = 0; for (int a = 0; a < i; a = a + 1) { P1 = P1 + Tcij[a, b]; P2 = P2 + Tvij[a, b]; } disp.AddConstr(P1, GRB.EQUAL, P2, "conservaciondeflujo" + i); } for (int a = 0; a < i; a = a + 1) { GRBLinExpr P1 = 0; GRBLinExpr P2 = 0; for (int b = 0; b < j; b = b + 1) { P1 = P1 + Tcij[a, b]; P2 = P2 + Tvij[a, b]; } disp.AddConstr(P1, GRB.EQUAL, P2, "conservaciondeflujo2" + i); } GRBLinExpr Pobj = 0; for (int a = 0; a < i; a = a + 1) { for (int b = 0; b < j; b = b + 1) { Pobj = Pobj + Ycij[a, b] + Yvij[a, b]; } } disp.Update(); disp.SetObjective(Pobj, GRB.MINIMIZE); disp.Optimize(); double sumayc = 0; double sumayv = 0; double sumatc = 0; double sumatv = 0; for (int a = 0; a < i; a = a + 1) { double sumajyc = 0; double sumajyv = 0; double sumajtc = 0; double sumajtv = 0; for (int b = 0; b < j; b = b + 1) { vectores.PlYc[a, b] = Convert.ToDouble(Ycij[a, b].X); vectores.PlYv[a, b] = Convert.ToDouble(Yvij[a, b].X); vectores.PlTc[a, b] = Convert.ToDouble(Tcij[a, b].X); vectores.PlTv[a, b] = Convert.ToDouble(Tvij[a, b].X); sumayc = sumayc + vectores.PlYc[a, b]; //suma todos los flujos llenos sumayv = sumayv + vectores.PlYv[a, b]; //suma todos los flujos vacios sumatc = sumatc + vectores.PlTc[a, b]; //suma todos los camiones llenos sumatv = sumatv + vectores.PlTv[a, b]; //suma todos los camiones vacios sumajyc = sumajyc + Convert.ToDouble(Ycij[a, b].X); //suma todo el flujo cargado al botadero "a" sumajyv = sumajyv + Convert.ToDouble(Yvij[a, b].X); //suma todo el flujo vacio al botadero "a" sumajtc = sumajtc + Convert.ToDouble(Tcij[a, b].X); //suma todos los camiones cargados yendo a botadero "a" sumajtv = sumajtv + Convert.ToDouble(Tvij[a, b].X); //suma todos los camiones vacios yendo a botadero "a" } vectores.PlYc[a, 20] = sumajyc; // deja total vectores.PlYv[a, 20] = sumajyv; // vectores.PlTc[a, 20] = sumajtc; // vectores.PlTv[a, 20] = sumajtv; // } for (int b = 0; b < j; b = b + 1) { double sumaiyc = 0; double sumaiyv = 0; double sumaitc = 0; double sumaitv = 0; for (int a = 0; a < i; a = a + 1) { sumaiyc = sumaiyc + Convert.ToDouble(Ycij[a, b].X); sumaiyv = sumaiyv + Convert.ToDouble(Yvij[a, b].X); sumaitc = sumaitc + Convert.ToDouble(Tcij[a, b].X); sumaitv = sumaitv + Convert.ToDouble(Tvij[a, b].X); } vectores.PlYc[30, b] = sumaiyc; vectores.PlYv[30, b] = sumaiyv; vectores.PlTc[30, b] = sumaitc; vectores.PlTv[30, b] = sumaitv; } vectores.PlYc[30, 20] = sumayc; vectores.PlYv[30, 20] = sumayv; vectores.PlTc[30, 20] = sumatc; vectores.PlTv[30, 20] = sumatv; _timenow.StateValue = vectores.PlTc[0, 20]; sr.serializa(vectores); sr.closeStream(); disp.Dispose(); env.Dispose(); return(ExitType.FirstExit); }
static void Main(string[] args) { int n = 9; int s = 3; if (args.Length < 1) { Console.Out.WriteLine("Usage: sudoku_cs filename"); return; } try { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); // Create 3-D array of model variables GRBVar[,,] vars = new GRBVar[n, n, n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int v = 0; v < n; v++) { string st = "G_" + i.ToString() + "_" + j.ToString() + "_" + v.ToString(); vars[i, j, v] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, st); } } } // Add constraints GRBLinExpr expr; // Each cell must take one value for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { expr = 0.0; for (int v = 0; v < n; v++) { expr.AddTerm(1.0, vars[i, j, v]); } string st = "V_" + i.ToString() + "_" + j.ToString(); model.AddConstr(expr == 1.0, st); } } // Each value appears once per row for (int i = 0; i < n; i++) { for (int v = 0; v < n; v++) { expr = 0.0; for (int j = 0; j < n; j++) { expr.AddTerm(1.0, vars[i, j, v]); } string st = "R_" + i.ToString() + "_" + v.ToString(); model.AddConstr(expr == 1.0, st); } } // Each value appears once per column for (int j = 0; j < n; j++) { for (int v = 0; v < n; v++) { expr = 0.0; for (int i = 0; i < n; i++) { expr.AddTerm(1.0, vars[i, j, v]); } string st = "C_" + j.ToString() + "_" + v.ToString(); model.AddConstr(expr == 1.0, st); } } // Each value appears once per sub-grid for (int v = 0; v < n; v++) { for (int i0 = 0; i0 < s; i0++) { for (int j0 = 0; j0 < s; j0++) { expr = 0.0; for (int i1 = 0; i1 < s; i1++) { for (int j1 = 0; j1 < s; j1++) { expr.AddTerm(1.0, vars[i0 * s + i1, j0 * s + j1, v]); } } string st = "Sub_" + v.ToString() + "_" + i0.ToString() + "_" + j0.ToString(); model.AddConstr(expr == 1.0, st); } } } // Fix variables associated with pre-specified cells StreamReader sr = File.OpenText(args[0]); for (int i = 0; i < n; i++) { string input = sr.ReadLine(); for (int j = 0; j < n; j++) { int val = (int)input[j] - 48 - 1; // 0-based if (val >= 0) { vars[i, j, val].LB = 1.0; } } } // Optimize model model.Optimize(); // Write model to file model.Write("sudoku.lp"); double[,,] x = model.Get(GRB.DoubleAttr.X, vars); Console.WriteLine(); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int v = 0; v < n; v++) { if (x[i, j, v] > 0.5) { Console.Write(v + 1); } } } Console.WriteLine(); } // Dispose of model and env 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.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.ModelSense = GRB.MINIMIZE; // 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].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].Start = 0.0; Console.WriteLine("Closing plant " + p + "\n"); break; } } // Use barrier to solve root relaxation model.Parameters.Method = GRB.METHOD_BARRIER; // Solve model.Optimize(); // Print solution Console.WriteLine("\nTOTAL COSTS: " + model.ObjVal); Console.WriteLine("SOLUTION:"); for (int p = 0; p < nPlants; ++p) { if (open[p].X > 0.99) { Console.WriteLine("Plant " + p + " open:"); for (int w = 0; w < nWarehouses; ++w) { if (transport[w, p].X > 0.0001) { Console.WriteLine(" Transport " + transport[w, p].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); } }
void BuildGRBModel() { _env = new GRBEnv("SolutionLog.log"); _env.Set(GRB.DoubleParam.MIPGap, 0.0); _env.Set(GRB.DoubleParam.TimeLimit, 500); _env.Set(GRB.DoubleParam.Heuristics, 0.5); _grbModel = new GRBModel(_env); //决策变量 foreach (Node n in Data.NodeSet) { n.Result_GenerateFlow = _grbModel.AddVar(0.0, Data.M, 0.0, GRB.CONTINUOUS, "g_" + n.ID); n.Result_IsServerLoacationSelected = _grbModel.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "x_" + n.ID); } foreach (Arc a in Data.ArcSet) { a.Result_FlowF = _grbModel.AddVar(0.0, Data.M, 0.0, GRB.CONTINUOUS, "fF_" + a.FromNode.ID + "_" + a.ToNode.ID); a.Result_FlowR = _grbModel.AddVar(0.0, Data.M, 0.0, GRB.CONTINUOUS, "fR_" + a.FromNode.ID + "_" + a.ToNode.ID); } _grbModel.Update(); //目标函数 GRBLinExpr expr1 = 0; foreach (Node n in Data.NodeSet) { expr1 += n.Result_IsServerLoacationSelected * Data.ServerInstalationFee; } GRBLinExpr expr2 = 0; foreach (Arc a in Data.ArcSet) { expr2 += (a.Result_FlowF + a.Result_FlowR) * Data.FlowFeePerUnit; } _grbModel.SetObjective(expr1 + expr2, GRB.MINIMIZE); //约束条件 foreach (Node n in Data.NodeSet) { _grbModel.AddConstr(n.Result_GenerateFlow <= n.Result_IsServerLoacationSelected * Data.M, "ct1_" + n.ID); } foreach (Node n in Data.NodeSet) { GRBLinExpr sum1 = 0; GRBLinExpr sum2 = 0; GRBLinExpr sum3 = 0; GRBLinExpr sum4 = 0; foreach (Arc a in n.ArcSet) { if (a.ToNode == n)//进 { sum1 += a.Result_FlowF; sum3 += a.Result_FlowR; } else//出 { sum2 += a.Result_FlowR; sum4 += a.Result_FlowF; } } _grbModel.AddConstr(n.Result_GenerateFlow + sum1 + sum2 == n.Demand + sum3 + sum4, "ct2_" + n.ID); } foreach (Arc a in Data.ArcSet) { _grbModel.AddConstr(a.Result_FlowF + a.Result_FlowR <= a.Capacity, "ct3_" + a.FromNode.ID + "_" + a.ToNode.ID); } }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[, ] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.ModelName = "assignment"; // Assignment variables: x[w][s] == 1 if worker w is assigned // to shift s. This is no longer a pure assignment model, so we must // use binary variables. GRBVar[,] x = new GRBVar[nWorkers, nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w, s] = model.AddVar(0, availability[w, s], 0, GRB.BINARY, Workers[w] + "." + Shifts[s]); } } // Slack variables for each shift constraint so that the shifts can // be satisfied GRBVar[] slacks = new GRBVar[nShifts]; for (int s = 0; s < nShifts; ++s) { slacks[s] = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, Shifts[s] + "Slack"); } // Variable to represent the total slack GRBVar totSlack = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "totSlack"); // Variables to count the total shifts worked by each worker GRBVar[] totShifts = new GRBVar[nWorkers]; for (int w = 0; w < nWorkers; ++w) { totShifts[w] = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, Workers[w] + "TotShifts"); } GRBLinExpr lhs; // Constraint: assign exactly shiftRequirements[s] workers // to each shift s, plus the slack for (int s = 0; s < nShifts; ++s) { lhs = new GRBLinExpr(); lhs.AddTerm(1.0, slacks[s]); for (int w = 0; w < nWorkers; ++w) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs == shiftRequirements[s], Shifts[s]); } // Constraint: set totSlack equal to the total slack lhs = new GRBLinExpr(); for (int s = 0; s < nShifts; ++s) { lhs.AddTerm(1.0, slacks[s]); } model.AddConstr(lhs == totSlack, "totSlack"); // Constraint: compute the total number of shifts for each worker for (int w = 0; w < nWorkers; ++w) { lhs = new GRBLinExpr(); for (int s = 0; s < nShifts; ++s) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs == totShifts[w], "totShifts" + Workers[w]); } // Objective: minimize the total slack model.SetObjective(1.0 * totSlack); // Optimize int status = solveAndPrint(model, totSlack, nWorkers, Workers, totShifts); if (status != GRB.Status.OPTIMAL) { return; } // Constrain the slack by setting its upper and lower bounds totSlack.UB = totSlack.X; totSlack.LB = totSlack.X; // Variable to count the average number of shifts worked GRBVar avgShifts = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "avgShifts"); // Variables to count the difference from average for each worker; // note that these variables can take negative values. GRBVar[] diffShifts = new GRBVar[nWorkers]; for (int w = 0; w < nWorkers; ++w) { diffShifts[w] = model.AddVar(-GRB.INFINITY, GRB.INFINITY, 0, GRB.CONTINUOUS, Workers[w] + "Diff"); } // Constraint: compute the average number of shifts worked lhs = new GRBLinExpr(); for (int w = 0; w < nWorkers; ++w) { lhs.AddTerm(1.0, totShifts[w]); } model.AddConstr(lhs == nWorkers * avgShifts, "avgShifts"); // Constraint: compute the difference from the average number of shifts for (int w = 0; w < nWorkers; ++w) { model.AddConstr(totShifts[w] - avgShifts == diffShifts[w], Workers[w] + "Diff"); } // Objective: minimize the sum of the square of the difference from the // average number of shifts worked GRBQuadExpr qobj = new GRBQuadExpr(); for (int w = 0; w < nWorkers; ++w) { qobj.AddTerm(1.0, diffShifts[w], diffShifts[w]); } model.SetObjective(qobj); // Optimize status = solveAndPrint(model, totSlack, nWorkers, Workers, totShifts); if (status != GRB.Status.OPTIMAL) { return; } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public void OptimalPlacement(ref List <Station> stationList, ref List <OHCAEvent> eventList) { int[,] a = new int[J, I]; for (int j = 0; j < J; j++) { for (int i = 0; i < I; i++) { a[j, i] = (Utils.GetDistance(stationList[i].lat, stationList[i].lon, eventList[j].lat, eventList[j].lon) < Utils.GOLDEN_TIME - 1.0 / 6.0) ? 1 : 0; } } try { GRBEnv env = new GRBEnv("Boutilier.log"); GRBModel model = new GRBModel(env); GRBVar[] y = new GRBVar[I]; for (int i = 0; i < I; i++) { y[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "y_" + i); } GRBVar[, ] z = new GRBVar[J, I]; for (int j = 0; j < J; j++) { for (int i = 0; i < I; i++) { z[j, i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "z_" + i + "," + j); } } GRBLinExpr obj_expr = 0.0; for (int i = 0; i < I; i++) { obj_expr.AddTerm(1.0, y[i]); } model.SetObjective(obj_expr, GRB.MINIMIZE); GRBLinExpr bigExpr = 0.0; for (int j = 0; j < J; j++) { GRBLinExpr expr = 0.0; for (int i = 0; i < I; i++) { expr.AddTerm(1, z[j, i]); } bigExpr.Add(expr); model.AddConstr(expr, GRB.LESS_EQUAL, 1.0, "c0_" + j); } model.AddConstr(bigExpr, GRB.GREATER_EQUAL, f / 100.0 * J, "c1"); for (int j = 0; j < J; j++) { for (int i = 0; i < I; i++) { model.AddConstr(z[j, i], GRB.LESS_EQUAL, a[j, i] * y[i], "c2_" + i + "," + j); } } model.Write("model_b.lp"); model.Optimize(); int optimstatus = model.Status; if (optimstatus == GRB.Status.INF_OR_UNBD) { model.Parameters.Presolve = 0; model.Optimize(); optimstatus = model.Status; } if (optimstatus == GRB.Status.OPTIMAL) { } else if (optimstatus == GRB.Status.INFEASIBLE) { Console.WriteLine("Model is unbounded"); } else { Console.WriteLine("Optimization was stopped with status = " + optimstatus); } List <Station> tempList = new List <Station>(); CloneList(stationList, tempList); stationList.Clear(); for (int i = 0; i < I; i++) { if (y[i].Get(GRB.DoubleAttr.X) > 0) { stationList.Add(tempList[i]); } } I = stationList.Count; coverList = new List <List <int> >(); for (int i = 0; i < I; i++) { coverList.Add(new List <int>()); } for (int j = 0; j < J; j++) { for (int i = 0; i < I; i++) { if (z[j, i].Get(GRB.DoubleAttr.X) > 0) { coverList[i].Add(j); } } } model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code : " + e.ErrorCode + ", " + e.Message); } }
private void RunOptimization() { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); List <List <GRBVar> > varsFromElements = new List <List <GRBVar> >(); //Variables: LoD for each element with their respective utility value for (var i = 0; i < _model.Elements.Count; i++) { var element = _model.Elements[i]; var allLoads = CalcUtil.GetAllCognitiveLoadsForElement(element); List <GRBVar> varsCurrentElement = new List <GRBVar>(); var lowerBound = 0.0; var upperBound = 0.0; for (var j = 0; j < allLoads.Count; j++) { //Fix element and current LoD if flag is set, i.e. lower and upper bound are 1.0 if (element.FixateElement) { //lowerBound = (j + 1) == element.CurrentLevelOfDetail ? 1.0 : 0.0; if (element.ElementIsInView) { lowerBound = (j + 1) == element.CurrentLevelOfDetail ? 1.0 : 0.0; } else { lowerBound = (j + 1) == element.MaxViewLevelOfDetail ? 1.0 : 0.0; } } //Omit element if omit-flag is set, ie lower and upper bound are 0.0 //also: minimum LoD is 1 for any element that is optimized upperBound = !element.OmitElement && j > 0 ? 1.0 : 0.0; if (lowerBound < 1.0 && upperBound > 0.0) { //element is in sight, therefore should be spatially anchored, not in view //if (element.ElementIsInView && (j + 1) <= 2) //{ // upperBound = 0.0; //} //else if (!element.ElementIsInView && ((j + 1) > element.MaxViewLevelOfDetail || (j + 1) < element.MinViewLevelOfDetail)) { upperBound = 0.0; } } //Disable changing the LoD by more than 1, ie set upper bound to 0.0 (except if element is fixated) //var absLoDDifference = Math.Abs(element.CurrentLevelOfDetail - 1 - j); //if (lowerBound < 1.0 && absLoDDifference > 1 && (j + 1) > 1) // upperBound = 0.0; GRBVar eLod = model.AddVar(lowerBound, upperBound, CalcUtil.GetObjectiveForElement(element, j + 1, _model), GRB.BINARY, "e_" + i + "_lod_" + j); varsCurrentElement.Add(eLod); } varsFromElements.Add(varsCurrentElement); } //Constraint: overall cognitive load must be below user's cognitive capacity GRBLinExpr lhs = 0.0; for (var i = 0; i < _model.Elements.Count; i++) { var element = _model.Elements[i]; var allLoads = CalcUtil.GetAllCognitiveLoadsForElement(element); for (var j = 0; j < allLoads.Count; j++) { var load = allLoads[j] + CalcUtil.GetTimeDependentCognitiveLoadOnsetPenalty(element, _model); lhs.AddTerm(load, varsFromElements[i][j]); } } model.AddConstr(lhs, GRB.LESS_EQUAL, _model.UserModel.CognitiveCapacity, "c_cog"); //Constraint: constraints to number of available slots lhs = 0.0; for (var i = 0; i < _model.Elements.Count; i++) { for (var j = 0; j < _model.Elements[i].MaxLevelOfDetail; j++) { lhs.AddTerm(1.0, varsFromElements[i][j]); } } model.AddConstr(lhs, GRB.GREATER_EQUAL, _model.NumMinPlacementSlots, "c_slots_min"); model.AddConstr(lhs, GRB.LESS_EQUAL, _model.NumMaxPlacementSlots, "c_slots_max"); //Constraint: only 1 LoD per Element for (var i = 0; i < _model.Elements.Count; i++) { lhs = 0.0; for (var j = 0; j < _model.Elements[i].MaxLevelOfDetail; j++) { lhs.AddTerm(1.0, varsFromElements[i][j]); } model.AddConstr(lhs, GRB.LESS_EQUAL, 1.0, "c" + i + "_lod"); } model.ModelSense = GRB.MAXIMIZE; model.Optimize(); var status = model.Status; _model.IsFeasible = !(status == GRB.Status.INF_OR_UNBD || status == GRB.Status.INFEASIBLE || status == GRB.Status.UNBOUNDED); if (_model.IsFeasible) { //UpdateModels(model, varsFromElements); StoreAllSolutions(model); Console.WriteLine(@"The model solved with cogLoad " + _model.UserModel.CognitiveCapacity + " / objective " + _model.Solutions[0].Objective); } else { Console.WriteLine(@"The model cannot be solved because it is infeasible or unbounded"); } model.Dispose(); env.Dispose(); }
public static GRBVar AddVar(this GRBModel _m, double lb, double ub, char type, string _prefix = null) { return(_m.AddVar(lb, ub, 0, type, _prefix)); }
public HttpResponseMessage Optimize(string RunName) { using (var dbConn = new ApplicationDbContext()) { //Variables for students, semesters, courses, and course/semester offerings students = dbConn.StudentPreferences.Where(m => m.IsActive == true).Include(m => m.Courses).Include(m => m.Student.CompletedCourses).OrderByDescending(m => m.Student.CompletedCourses.Count()).ToArray(); crssems = dbConn.CourseSemesters.Where(m => m.IsActive == true).Include(m => m.Course).Include(m => m.Semester).ToArray(); courses = crssems.Select(m => m.Course).Distinct().ToArray(); sems = crssems.Select(m => m.Semester).Distinct().OrderBy(m => m.Type).OrderBy(m => m.Year).ToArray(); var completed = dbConn.CompletedCourses.ToList(); try { GRBEnv env = new GRBEnv("mip1.log"); GRBModel model = new GRBModel(env); model.Set(GRB.StringAttr.ModelName, "Course Optimizer"); GRBVar[,] slacks = new GRBVar[courses.Length, sems.Length]; //Assignment of student, course, and semester. Student must have a desire to take the coure, has not taken the course, and the course is offered to be included GRBVar[,,] CourseAllocation = new GRBVar[students.Length, courses.Length, sems.Length]; for (int i = 0; i < students.Length; i++) { for (int j = 0; j < courses.Length; j++) { for (int k = 0; k < sems.Length; k++) { if (students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID) && crssems.Contains(crssems.SingleOrDefault(m => m.Course == courses[j] && m.Semester == sems[k]))) CourseAllocation[i, j, k] = model.AddVar(0, 1, 1, GRB.BINARY, "students." + (i + 1).ToString() + "_Course." + (j + 1).ToString() + "_Semester." + (k + 1).ToString()); else CourseAllocation[i, j, k] = model.AddVar(0, 0, 1, GRB.BINARY, "students." + (i + 1).ToString() + "_Course." + (j + 1).ToString() + "_Semester." + (k + 1).ToString()); } } } model.Set(GRB.IntAttr.ModelSense, 1); model.Update(); //MUST TAKE DESIRED COURSE ONLY ONCE //Constrains the students to only take courses they desire once and for when the course is offered and does not allow a repeat of a course in another semester for (int i = 0; i < students.Length; i++) { for (int j = 0; j < courses.Length; j++) { if (students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID)) { GRBLinExpr constStudentDesiredCourses = 0.0; for (int k = 0; k < sems.Length; k++) { if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year)) constStudentDesiredCourses.AddTerm(1.0, CourseAllocation[i, j, k]); } String sStudentDesiredCourses = "DesiredCourse." + j + 1 + "_Student." + i + 1; model.AddConstr(constStudentDesiredCourses == 1, sStudentDesiredCourses); } } //MAX COURSES PER SEMESTER //Constrains the students to only have a maximum number of 2 courses per semester. for (int k = 0; k < sems.Length; k++) { GRBLinExpr constMaxPerSem = 0.0; for (int j = 0; j < courses.Length; j++) { if (!completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID) && (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year))) constMaxPerSem.AddTerm(1, CourseAllocation[i, j, k]); } String sCourseSem = "maxCourseStudent." + i + 1 + "_Semester." + k + 1; model.AddConstr(constMaxPerSem <= MAX_COURSES_PER_SEMESTER, sCourseSem); } //PREREQUISITES //Constrains the students to take prerequisite courses prior to taking a course that needs the prerequisite for (int j = 0; j < courses.Length; j++) { if (courses[j].Prerequisites.Any() && students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID)) { foreach (var prereq in courses[j].Prerequisites) { int prereqIndex = Array.IndexOf(courses, prereq); GRBLinExpr coursePrereqConst1 = 0.0; GRBLinExpr coursePrereqConst2 = 0.0; if (!completed.Any(m => m.GaTechId == students[i].GaTechId && m.Course.ID == prereq.ID)) { for (int k = 0; k < sems.Length; k++) { if (prereqIndex >= 0) { coursePrereqConst1.AddTerm(k + 1, CourseAllocation[i, prereqIndex, k]); coursePrereqConst2.AddTerm(k, CourseAllocation[i, j, k]); } } } model.AddConstr(coursePrereqConst1, GRB.LESS_EQUAL, coursePrereqConst2, "PREREQ_Student" + i + "_Course+" + j + "_Prereq" + prereqIndex); } } } } //SENIORITY //Students are already ordered from dB query by seniority in descending order and puts a preference to senior students over the next student that desires that //same course with less seniority. for (int j = 0; j < courses.Length; j++) { for (int i = 0; i < students.Length - 1; i++) { if (students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID)) { int SemsRemain = (students[i].Courses.Count - students[i].Student.CompletedCourses.Count) / 2 + (students[i].Courses.Count - students[i].Student.CompletedCourses.Count) % 2; for (int n = i + 1; n < students.Length; n++) { if (students[n].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[n].GaTechId && courses[j].ID == m.Course_ID)) { GRBLinExpr seniority = 0.0; for (int k = 0; k < sems.Length; k++) { if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year)) { if (k <= SemsRemain) { seniority.AddTerm(1.0, CourseAllocation[i, j, k]); seniority.AddTerm(-1.0, CourseAllocation[n, j, k]); } else { seniority.AddTerm(-1.0, CourseAllocation[i, j, k]); seniority.AddTerm(1.0, CourseAllocation[n, j, k]); } } } model.AddConstr(seniority, GRB.GREATER_EQUAL, 0, "Seniority for Student." + students[i] + "_Course." + courses[j]); break; } } } } } //Add the slack variable for all semester & course offerings then constrain the maximum number of students //to take a couse in a semester. for (int k = 0; k < sems.Length; k++) { for (int j = 0; j < courses.Length; j++) { if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year)) { slacks[j, k] = model.AddVar(0, GRB.INFINITY, 0, GRB.INTEGER, sems[k].Type.ToString() + "." + sems[k].Year.ToString() + "." + courses[j].Name + ".Slacks"); GRBLinExpr constMaxStudCrsSem = 0.0; for (int i = 0; i < students.Length; i++) { if (!completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID)) constMaxStudCrsSem.AddTerm(1.0, CourseAllocation[i, j, k]); } model.Update(); constMaxStudCrsSem.AddTerm(-1.0, slacks[j, k]); model.AddConstr(constMaxStudCrsSem <= crssems.Single(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year).StudentLimit, sems[k].Type.ToString() + "." + sems[k].Year.ToString() + "." + courses[j].Name); } } } //Add total slack to the optimization model for all courses in the semesters they are offered. GRBVar totSlack = model.AddVar(0, GRB.INFINITY, 0, GRB.INTEGER, "totSlack"); GRBLinExpr lhs = new GRBLinExpr(); lhs.AddTerm(-1.0, totSlack); for (int j = 0; j < courses.Length; j++) { for (int k = 0; k < sems.Length; k++) { if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year)) lhs.AddTerm(1.0, slacks[j, k]); } } model.Update(); model.AddConstr(lhs, GRB.EQUAL, 0, "totSlack"); // Objective: minimize the total slack GRBLinExpr obj = new GRBLinExpr(); obj.AddTerm(1.0, totSlack); model.SetObjective(obj); //Optimize the model to minimize the total slack and maximize students to course offerings based on input variables and constraints. model.Optimize(); //Write Results optimization results to database writeResults(CourseAllocation, students, courses, sems, crssems, dbConn, Convert.ToInt32(model.Get(GRB.DoubleAttr.ObjVal)), RunName); //Clean-Up model.Dispose(); env.Dispose(); } catch (Exception e) { return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "An Error occured while running the optimization."); } } return Request.CreateResponse(HttpStatusCode.OK); }
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) { int n = 9; int s = 3; if (args.Length < 1) { Console.Out.WriteLine("Usage: sudoku_cs filename"); return; } try { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); // Create 3-D array of model variables GRBVar[,,] vars = new GRBVar[n,n,n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int v = 0; v < n; v++) { string st = "G_" + i.ToString() + "_" + j.ToString() + "_" + v.ToString(); vars[i,j,v] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, st); } } } // Integrate variables into model model.Update(); // Add constraints GRBLinExpr expr; // Each cell must take one value for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { expr = 0.0; for (int v = 0; v < n; v++) expr += vars[i,j,v]; string st = "V_" + i.ToString() + "_" + j.ToString(); model.AddConstr(expr == 1.0, st); } } // Each value appears once per row for (int i = 0; i < n; i++) { for (int v = 0; v < n; v++) { expr = 0.0; for (int j = 0; j < n; j++) expr += vars[i,j,v]; string st = "R_" + i.ToString() + "_" + v.ToString(); model.AddConstr(expr == 1.0, st); } } // Each value appears once per column for (int j = 0; j < n; j++) { for (int v = 0; v < n; v++) { expr = 0.0; for (int i = 0; i < n; i++) expr += vars[i,j,v]; string st = "C_" + j.ToString() + "_" + v.ToString(); model.AddConstr(expr == 1.0, st); } } // Each value appears once per sub-grid for (int v = 0; v < n; v++) { for (int i0 = 0; i0 < s; i0++) { for (int j0 = 0; j0 < s; j0++) { expr = 0.0; for (int i1 = 0; i1 < s; i1++) { for (int j1 = 0; j1 < s; j1++) { expr += vars[i0*s+i1,j0*s+j1,v]; } } string st = "Sub_" + v.ToString() + "_" + i0.ToString() + "_" + j0.ToString(); model.AddConstr(expr == 1.0, st); } } } // Update model model.Update(); // Fix variables associated with pre-specified cells StreamReader sr = File.OpenText(args[0]); for (int i = 0; i < n; i++) { string input = sr.ReadLine(); for (int j = 0; j < n; j++) { int val = (int) input[j] - 48 - 1; // 0-based if (val >= 0) vars[i,j,val].Set(GRB.DoubleAttr.LB, 1.0); } } // Optimize model model.Optimize(); // Write model to file model.Write("sudoku.lp"); double[,,] x = model.Get(GRB.DoubleAttr.X, vars); Console.WriteLine(); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int v = 0; v < n; v++) { if (x[i,j,v] > 0.5) { Console.Write(v+1); } } } Console.WriteLine(); } // Dispose of model and env 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 GRBVar AddToModel(GRBModel model) { return model.AddVar(lowerBound, upperBound, ObjectiveCoefficient, variableType, name); }
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); } }