static void Main() { try { GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); // Create variables double[] ub = { 1, 1, 2 }; double[] obj = { -2, -1, -1 }; string[] names = { "x0", "x1", "x2" }; GRBVar[] x = model.AddVars(null, ub, obj, null, names); // Integrate new variables model.Update(); // Add first SOS1: x0=0 or x1=0 GRBVar[] sosv1 = { x[0], x[1] }; double[] soswt1 = { 1, 2 }; model.AddSOS(sosv1, soswt1, GRB.SOS_TYPE1); // Add second SOS1: x0=0 or x2=0 GRBVar[] sosv2 = { x[0], x[2] }; double[] soswt2 = { 1, 2 }; model.AddSOS(sosv2, soswt2, GRB.SOS_TYPE1); // Optimize model model.Optimize(); for (int i = 0; i < 3; i++) { Console.WriteLine(x[i].Get(GRB.StringAttr.VarName) + " " + x[i].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(); GRBModel model = new GRBModel(env); // Create variables double[] ub = {1, 1, 2}; double[] obj = {-2, -1, -1}; string[] names = {"x0", "x1", "x2"}; GRBVar[] x = model.AddVars(null, ub, obj, null, names); // Integrate new variables model.Update(); // Add first SOS1: x0=0 or x1=0 GRBVar[] sosv1 = {x[0], x[1]}; double[] soswt1 = {1, 2}; model.AddSOS(sosv1, soswt1, GRB.SOS_TYPE1); // Add second SOS1: x0=0 or x2=0 GRBVar[] sosv2 = {x[0], x[2]}; double[] soswt2 = {1, 2}; model.AddSOS(sosv2, soswt2, GRB.SOS_TYPE1); // Optimize model model.Optimize(); for (int i = 0; i < 3; i++) Console.WriteLine(x[i].Get(GRB.StringAttr.VarName) + " " + x[i].Get(GRB.DoubleAttr.X)); // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
protected GRBVar[] CreatePermutationVariable() { var ub = new double[_k]; var obj = new double[_k]; var type = new char[_k]; for (var i = 0; i < _k; i++) { ub[i] = _k - 1; obj[i] = 0; type[i] = GRB.INTEGER; } return(_model.AddVars(null, ub, obj, type, null, 0, _k)); }
public static GRBVar[,] AddVars(this GRBModel _m, int _width, int _height, double lb, double ub, char type) { var vars = _m.AddVars(Enumerable.Repeat(lb, _width * _height).ToArray(), Enumerable.Repeat(ub, _width * _height).ToArray(), null, Enumerable.Repeat(type, _width * _height).ToArray(), null); var i = 0; var res = new GRBVar[_width, _height]; for (var y = 0; y < _height; y++) { for (var x = 0; x < _width; x++) { res[x, y] = vars[i++]; } } return(res); }
public static GRBVar[,] AddVars(this GRBModel _m, int _width, int _height, double lb, double ub, char type, string _prefix = null) { var vars = _m.AddVars(Enumerable.Repeat(lb, _width * _height).ToArray(), Enumerable.Repeat(ub, _width * _height).ToArray(), null, Enumerable.Repeat(type, _width * _height).ToArray(), _prefix == null ? null : Enumerable.Range(0, _width * _height).Select(j => $"{_prefix}[{j % _width},{j/_width}]").ToArray() ); var i = 0; var res = new GRBVar[_width, _height]; for (var y = 0; y < _height; y++) { for (var x = 0; x < _width; x++) { res[x, y] = vars[i++]; } } return(res); }
public static GRBVar[,,,] AddVars(this GRBModel _m, int _width, int _height, int _depth, int _d4, double lb, double ub, char type, string _prefix = null) { var vars = _m.AddVars(Enumerable.Repeat(lb, _width * _height * _depth * _d4).ToArray(), Enumerable.Repeat(ub, _width * _height * _depth * _d4).ToArray(), null, Enumerable.Repeat(type, _width * _height * _depth * _d4).ToArray(), _prefix == null ? null : Enumerable.Range(0, _width * _height * _depth * _d4).Select(j => $"{_prefix}[{j % _width},{(j/_width) % _height},{(j/_width/_height) % _depth},{j/_width/_height/_depth}]").ToArray() ); var i = 0; var res = new GRBVar[_width, _height, _depth, _d4]; for (var a = 0; a < _d4; a++) { for (var z = 0; z < _depth; z++) { for (var y = 0; y < _height; y++) { for (var x = 0; x < _width; x++) { res[x, y, z, a] = vars[i++]; } } } } return(res); }
protected static bool dense_optimize(GRBEnv env, int rows, int cols, double[] c, // linear portion of objective function double[,] Q, // quadratic portion of objective function double[,] A, // constraint matrix char[] sense, // constraint senses double[] rhs, // RHS vector double[] lb, // variable lower bounds double[] ub, // variable upper bounds char[] vtype, // variable types (continuous, binary, etc.) double[] solution) { bool success = false; try { GRBModel model = new GRBModel(env); // Add variables to the model GRBVar[] vars = model.AddVars(lb, ub, null, vtype, null); model.Update(); // Populate A matrix for (int i = 0; i < rows; i++) { GRBLinExpr expr = new GRBLinExpr(); for (int j = 0; j < cols; j++) if (A[i,j] != 0) expr.AddTerm(A[i,j], vars[j]); // Note: '+=' would be much slower model.AddConstr(expr, sense[i], rhs[i], ""); } // Populate objective GRBQuadExpr obj = new GRBQuadExpr(); if (Q != null) { for (int i = 0; i < cols; i++) for (int j = 0; j < cols; j++) if (Q[i,j] != 0) obj.AddTerm(Q[i,j], vars[i], vars[j]); // Note: '+=' would be much slower for (int j = 0; j < cols; j++) if (c[j] != 0) obj.AddTerm(c[j], vars[j]); // Note: '+=' would be much slower model.SetObjective(obj); } // Solve model model.Optimize(); // Extract solution if (model.Get(GRB.IntAttr.Status) == GRB.Status.OPTIMAL) { success = true; for (int j = 0; j < cols; j++) solution[j] = vars[j].Get(GRB.DoubleAttr.X); } model.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } return success; }
static void Main(string[] args) { int round; List <int> deglist = new List <int>(); //StreamWriter MaxDegT = new StreamWriter("MaxdegreeTerms.txt"); int startround = 960; //the target round runs from 960 to 1152. for (round = startround; round < 1153; round++) { GRBEnv env = new GRBEnv("Trvium.log"); GRBModel model = new GRBModel(env); Console.Write("****************** The " + round.ToString() + "-th round ******************\n"); //设置gurobi不输出中间结果 model.Parameters.LogToConsole = 0; int[] pos = new int[] { 65, 92, 161, 176, 242, 287 };//6个输出位置 65,92, 161, 176, 242, 287 //int[] pos = new int[3] { };//6个输出位置 GRBVar[] IV = model.AddVars(80, GRB.BINARY); GRBVar[] Key = model.AddVars(80, GRB.BINARY); for (int i = 0; i < 80; i++) { IV[i].VarName = "IV" + i.ToString(); //IV变量,命名为IV0-IV79 Key[i].VarName = "Key" + i.ToString(); //IV变量,命名为Key0-Key79 } GRBVar[] s = model.AddVars(288, GRB.BINARY); for (int i = 0; i < 288; i++) { s[i].VarName = "var" + i.ToString(); //288个寄存器,命名为var0-var288 } char[] FlagS = new char[288]; //288个寄存器的Flag GRBVar[] NewVars = model.AddVars(30 * round, GRB.BINARY); for (int i = 0; i < NewVars.Length; i++) { NewVars[i].VarName = "y" + i.ToString(); //每过一次更新许需要加30个变量,总共为30*round,命名为y0-y300*round } char[] FlagNewVars = new char[30 * round]; //新加变量的Flag List <uint> cube = new List <uint>() { 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78 }; List <uint> ivbits_set_to_1 = new List <uint>() { }; List <uint> ivbits_set_to_0 = new List <uint>() { }; for (uint i = 0; i < 80; i = i + 1) { ivbits_set_to_0.Add(i); } for (int i = 0; i < cube.Count; i++) { ivbits_set_to_0.Remove(cube[i]); } for (int i = 0; i < cube.Count; i++) { Console.Write(cube[i] + " "); } Console.WriteLine(); List <UInt32> Noncube = new List <uint>() { 0x0, 0x0, 0x0 }; //Noncube stores the value of the non-cube variables //for each iv bit which is set to 1, set the corresponding bit of Noncube to 1. for (int i = 0; i < ivbits_set_to_1.Count; i++) { Noncube[(int)ivbits_set_to_1[i] >> 5] |= (uint)(0x01 << ((int)(ivbits_set_to_1[i] & 0x1f))); } GRBLinExpr ChooseIV = new GRBLinExpr();// for (int i = 0; i < cube.Count; i++) { ChooseIV.AddTerm(1.0, IV[cube[i]]); } //the bits set to constants List <int> chokey = new List <int>() { 1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 64, 65, 66, 67, 68, 70, 71, 73, 74, 76, 77, 79 }; //pick up the key variables which are not fixed. //i.e. keydeg= k_i1+k_i2+...+k_in, where k_i1,k_i2,...,k_im are the key bits which are not fixed GRBLinExpr keydeg = new GRBLinExpr(); for (int i = 0; i < 80; i++) { if (!chokey.Contains(i)) { keydeg.AddTerm(1.0, Key[i]); } } //set maximizing the linear expression keydeg as the objective function of our model //Hence, we could obtain the upper bound of the degree of the superpoly of the chosen cube. model.SetObjective(keydeg, GRB.MAXIMIZE); //in this function, we set the conditions which are imposed to the key bits and iv bits //before running, it needs to set some parameters, such as the key bits set to 0/1 and so on, in this function, initial(model, s, FlagS, cube, Noncube, IV, Key); int VarNumber = 0; //describe the propagation of the division property with flag through Trivium for (int i = 1; i <= round; i++) { Triviumcore(model, s, FlagS, NewVars, FlagNewVars, ref VarNumber); } for (int i = 0; i < 288; i++) { if (!pos.Contains(i)) { model.AddConstr(s[i] == 0, "a" + i.ToString()); } } GRBLinExpr expr = new GRBLinExpr(); for (int i = 0; i < pos.Count(); i++) { expr.AddTerm(1.0, s[pos[i]]); } model.AddConstr(expr == 1, "t1"); //solve the MILP model. model.Optimize(); int currentdeg = 0; //outout the solution int NO = 0; // is the model is feasible the upper bound of the degree of the superpoly is large than 0. // In this case, we output a possible term of degree d, where d is the upper bound of the degree of the superpoly. if (model.SolCount > 0) { StreamWriter MaxDegT = new StreamWriter("MaxdegreeTerms.txt", true); currentdeg = (int)model.ObjVal; NO++; Console.WriteLine("****************No." + round + "********************\n"); //MaxDegT.WriteLine("****************No." + NO + "********************\n"); MaxDegT.WriteLine("*****************round" + round + "**********************\n"); MaxDegT.Write("Upper bound of degree of superpoly: "); Console.WriteLine(model.ObjVal); MaxDegT.WriteLine(model.ObjVal); GRBLinExpr ChoIV = new GRBLinExpr();//选择能到达最大次数的IV; // for (int i = 0; i < cube.Count; i++) int sumy = 0; for (int i = 0; i < 80; i++) { Console.Write(Key[i].X + ","); } Console.WriteLine(); MaxDegT.Write("One possible terms of degree " + model.ObjVal + " is : "); for (int i = 0; i < 80; i++) { if (Key[i].X > 0.781) { sumy++; MaxDegT.Write(i + ","); Console.Write(i + ","); } } MaxDegT.Write("\n\n***********************************************\n"); Console.Write("\n***********************************************\n"); for (int i = 0; i < cube.Count(); i++) { // Console.Write(IV[i].X + ","); if (s[cube[i]].X > 0.781) { sumy++; MaxDegT.Write(i + ","); Console.Write(i + ","); } } Console.WriteLine(); MaxDegT.WriteLine(); MaxDegT.Close(); } if (model.SolCount > 0) { deglist.Add((int)model.ObjVal); } else//if the model is imfeasible, then the degree of the superpoly is upper bounded by 0. { deglist.Add(0); StreamWriter MaxDegT = new StreamWriter("MaxdegreeTerms.txt", true); MaxDegT.WriteLine("*****************round" + round + "**********************\n"); MaxDegT.WriteLine("Upper bound of degree of superpoly: 0"); MaxDegT.Write("\n***********************************************\n"); MaxDegT.WriteLine(); MaxDegT.Close(); } model.Dispose(); env.Dispose(); } //MaxDegT.Close(); for (int i = startround; i < round; i++) { Console.Write(i.ToString() + " " + deglist[i - startround].ToString() + "\n"); } Console.ReadLine(); }
public static void Main() { try { int n = 5; int m = 5; double[] c = new double[] { 0.5, 0.8, 0.5, 0.1, -1 }; double[,] A = new double[, ] { { 0, 0, 0, 1, -1 }, { 0, 0, 1, 1, -1 }, { 1, 1, 0, 0, -1 }, { 1, 0, 1, 0, -1 }, { 1, 0, 0, 1, -1 } }; double[] xpts = new double[] { -1, 0, 0, 0, 1 }; double[] ypts = new double[] { 2, 1, 0, 1, 2 }; // Env and model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.ModelName = "gc_pwl_cs"; // Add variables, set bounds and obj coefficients GRBVar[] x = model.AddVars(n, GRB.CONTINUOUS); for (int i = 0; i < n; i++) { x[i].LB = -GRB.INFINITY; x[i].Obj = c[i]; } GRBVar[] y = model.AddVars(n, GRB.CONTINUOUS); // Set objective to maximize model.ModelSense = GRB.MAXIMIZE; // Add linear constraints for (int i = 0; i < m; i++) { GRBLinExpr le = 0.0; for (int j = 0; j < n; j++) { le.AddTerm(A[i, j], x[j]); } model.AddConstr(le, GRB.LESS_EQUAL, 0, "cx" + i); } GRBLinExpr le1 = 0.0; for (int j = 0; j < n; j++) { le1.AddTerm(1.0, y[j]); } model.AddConstr(le1, GRB.LESS_EQUAL, 3, "cy"); // Add piecewise constraints for (int j = 0; j < n; j++) { model.AddGenConstrPWL(x[j], y[j], xpts, ypts, "pwl" + j); } // Optimize model model.Optimize(); for (int j = 0; j < n; j++) { Console.WriteLine("x[" + j + "] = " + x[j].X); } Console.WriteLine("Obj: " + model.ObjVal); // Dispose of model and environment model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public static GRBVar[] AddVars(this GRBModel _m, int _count, double lb, double ub, char type) { return(_m.AddVars(Enumerable.Repeat(lb, _count).ToArray(), Enumerable.Repeat(ub, _count).ToArray(), null, Enumerable.Repeat(type, _count).ToArray(), null)); }
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); }
static void Main(string[] args) { //for (int i = 0; i < 26; i++) // Console.Write(3*i + ","); //Console.ReadKey(); GRBEnv env = new GRBEnv("Kreyium.log"); int round = 892; GRBModel model = new GRBModel(env); int[] pos = new int[7] { 65, 92, 161, 176, 242, 287, 415 }; //7个输出位置 GRBVar[] s = model.AddVars(544, GRB.BINARY); for (int i = 0; i < 544; i++) { s[i].VarName = "var" + i.ToString(); //288个寄存器,命名为var0-var288 } char[] FlagS = new char[544]; //288个寄存器的Flag GRBVar[] NewVars = model.AddVars(34 * round, GRB.BINARY); for (int i = 0; i < NewVars.Length; i++) { NewVars[i].VarName = "y" + i.ToString(); //每过一次更新许需要加30个变量,总共为30*round,命名为y0-y300*round } char[] FlagNewVars = new char[34 * round]; //新加变量的Flag GRBVar[] IV = model.AddVars(128, GRB.BINARY); for (int i = 0; i < 128; i++) { IV[i].VarName = "IV" + i.ToString();//128个IV变量 } GRBVar[] Key = model.AddVars(128, GRB.BINARY); for (int i = 0; i < 128; i++) { Key[i].VarName = "Key" + i.ToString();//128个Key变量 } // List<uint> cube = new List<uint>() { 1, 3, 5, 7, 9, 11, 13, 16, 18, 20, 22, 24, 26, 28, 31, 33, 35, 37, 39, 41, 43, 46, // 48, 50, 52, 54, 61, 63, 65, 67, 69, 71, 73, 76, 78, 80, 82, 84, 86, 88, 90, 92, 95, // 97, 99, 101, 103, 106, 108, 110, 112, 114, 116, 118, 120, 125, 127};//cube变量 //dcc19 // List<uint> cube = new List<uint>() { 0,2,4,6,8,10,12,15,17,19,21,24,26,28,30,32,34,36,39,41,43,45,47,49,52,54,56,58, // 60,62,67,69,71,73,75,80,82,84,86,89,91,93,95,97,99,102,104,106,108,110,112,114, // 117,119,121,123};//cube变量 //List<uint> cube = new List<uint>() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 43, 45, 46, 47, 48, 49, 50, 51, 52, 54, 56, 59, 61, 63, 65, 67, 69, 71, 74, 76, 78, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}; //dis880 try 892 //List<uint> cube =new List<uint>(){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,29,31,33,35,37,39,41,44,46,48,50,52,54,56,59,61,63,65,67,69,72,74,76,78,80,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}; List <uint> cube = new List <uint>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 39, 41, 43, 44, 45, 46, 47, 48, 49, 50, 52, 54, 57, 59, 61, 63, 65, 67, 69, 72, 74, 76, 78, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127 }; List <int> keyset = new List <int>() { }; for (int i = 0; i < 128; i++) { keyset.Add(i); } for (int i = 0; i < cube.Count(); i++) { Console.Write(cube[i] + " "); } Console.WriteLine(); List <UInt32> Noncube = new List <uint>() { 0x0, 0x0, 0x0, 0x0 }; GRBLinExpr ChooseKey = new GRBLinExpr();//超多项式中可能含有的密钥变量集合 int VarNumber = 0; initial(model, s, FlagS, cube, Noncube, keyset, ChooseKey, IV, Key);//初始化设置 for (int i = 1; i <= round; i++) { Triviumcore(model, s, FlagS, NewVars, FlagNewVars, ref VarNumber); } for (int i = 0; i < 544; i++) { if (!pos.Contains(i)) { model.AddConstr(s[i] == 0, "a" + i.ToString()); } } GRBLinExpr expr = new GRBLinExpr(); for (int i = 0; i < 7; i++) { expr.AddTerm(1.0, s[pos[i]]); } model.AddConstr(expr == 1, "t1"); model.Optimize(); if (model.SolCount > 0) { Console.WriteLine(model.ObjVal); } else { Console.WriteLine("************************************"); Console.WriteLine("Model is infeasible!!!"); Console.WriteLine("************************************"); } model.Dispose(); env.Dispose(); Console.ReadKey(); }
static void Main() { try{ // Sample data int groundSetSize = 10; double[] objCoef = new double[] { 32, 32, 15, 15, 6, 6, 1, 1, 1, 1 }; double[] knapsackCoef = new double[] { 16, 16, 8, 8, 4, 4, 2, 2, 1, 1 }; double Budget = 33; int e, status, nSolutions; // Create environment GRBEnv env = new GRBEnv("poolsearch_cs.log"); // Create initial model GRBModel model = new GRBModel(env); model.ModelName = "poolsearch_cs"; // Initialize decision variables for ground set: // x[e] == 1 if element e is chosen GRBVar[] Elem = model.AddVars(groundSetSize, GRB.BINARY); model.Set(GRB.DoubleAttr.Obj, Elem, objCoef, 0, groundSetSize); for (e = 0; e < groundSetSize; e++) { Elem[e].VarName = string.Format("El{0}", e); } // Constraint: limit total number of elements to be picked to be at most // Budget GRBLinExpr lhs = new GRBLinExpr(); for (e = 0; e < groundSetSize; e++) { lhs.AddTerm(knapsackCoef[e], Elem[e]); } model.AddConstr(lhs, GRB.LESS_EQUAL, Budget, "Budget"); // set global sense for ALL objectives model.ModelSense = GRB.MAXIMIZE; // Limit how many solutions to collect model.Parameters.PoolSolutions = 1024; // Limit the search space by setting a gap for the worst possible solution that will be accepted model.Parameters.PoolGap = 0.10; // do a systematic search for the k-best solutions model.Parameters.PoolSearchMode = 2; // save problem model.Write("poolsearch_cs.lp"); // Optimize model.Optimize(); // Status checking status = model.Status; if (status == GRB.Status.INF_OR_UNBD || status == GRB.Status.INFEASIBLE || status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is infeasible or unbounded"); return; } if (status != GRB.Status.OPTIMAL) { Console.WriteLine("Optimization was stopped with status {0}", status); return; } // Print best selected set Console.WriteLine("Selected elements in best solution:"); Console.Write("\t"); for (e = 0; e < groundSetSize; e++) { if (Elem[e].X < .9) { continue; } Console.Write("El{0} ", e); } Console.WriteLine(); // Print number of solutions stored nSolutions = model.SolCount; Console.WriteLine("Number of solutions found: {0}", nSolutions); // Print objective values of solutions for (e = 0; e < nSolutions; e++) { model.Parameters.SolutionNumber = e; Console.Write("{0} ", model.PoolObjVal); if (e % 15 == 14) { Console.WriteLine(); } } Console.WriteLine(); // Print fourth best set if available if (nSolutions >= 4) { model.Parameters.SolutionNumber = 3; Console.WriteLine("Selected elements in fourth best solution:"); Console.Write("\t"); for (e = 0; e < groundSetSize; e++) { if (Elem[e].Xn < .9) { continue; } Console.Write("El{0} ", e); } Console.WriteLine(); } model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: {0}. {1}", e.ErrorCode, e.Message); } }
static void Main() { try { // Sample data int groundSetSize = 20; int nSubsets = 4; int Budget = 12; double[,] Set = new double[, ] { { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }, { 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0 } }; int[] SetObjPriority = new int[] { 3, 2, 2, 1 }; double[] SetObjWeight = new double[] { 1.0, 0.25, 1.25, 1.0 }; int e, i, status, nSolutions; // Create environment GRBEnv env = new GRBEnv("multiobj_cs.log"); // Create initial model GRBModel model = new GRBModel(env); model.ModelName = "multiobj_cs"; // Initialize decision variables for ground set: // x[e] == 1 if element e is chosen for the covering. GRBVar[] Elem = model.AddVars(groundSetSize, GRB.BINARY); for (e = 0; e < groundSetSize; e++) { string vname = string.Format("El{0}", e); Elem[e].VarName = vname; } // Constraint: limit total number of elements to be picked to be at most // Budget GRBLinExpr lhs = new GRBLinExpr(); for (e = 0; e < groundSetSize; e++) { lhs.AddTerm(1.0, Elem[e]); } model.AddConstr(lhs, GRB.LESS_EQUAL, Budget, "Budget"); // Set global sense for ALL objectives model.ModelSense = GRB.MAXIMIZE; // Limit how many solutions to collect model.Parameters.PoolSolutions = 100; // Set and configure i-th objective for (i = 0; i < nSubsets; i++) { string vname = string.Format("Set{0}", i); GRBLinExpr objn = new GRBLinExpr(); for (e = 0; e < groundSetSize; e++) { objn.AddTerm(Set[i, e], Elem[e]); } model.SetObjectiveN(objn, i, SetObjPriority[i], SetObjWeight[i], 1.0 + i, 0.01, vname); } // Save problem model.Write("multiobj_cs.lp"); // Optimize model.Optimize(); // Status checking status = model.Status; if (status == GRB.Status.INF_OR_UNBD || status == GRB.Status.INFEASIBLE || status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is infeasible or unbounded"); return; } if (status != GRB.Status.OPTIMAL) { Console.WriteLine("Optimization was stopped with status {0}", status); return; } // Print best selected set Console.WriteLine("Selected elements in best solution:"); Console.Write("\t"); for (e = 0; e < groundSetSize; e++) { if (Elem[e].X < .9) { continue; } Console.Write("El{0} ", e); } Console.WriteLine(); // Print number of solutions stored nSolutions = model.SolCount; Console.WriteLine("Number of solutions found: {0}", nSolutions); // Print objective values of solutions if (nSolutions > 10) { nSolutions = 10; } Console.WriteLine("Objective values for first {0} solutions:", nSolutions); for (i = 0; i < nSubsets; i++) { model.Parameters.ObjNumber = i; Console.Write("\tSet" + i); for (e = 0; e < nSolutions; e++) { model.Parameters.SolutionNumber = e; Console.Write("{0,8}", model.ObjNVal); } Console.WriteLine(); } model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code = {0}", e); Console.WriteLine(e.Message); } }
public override Schedule Generate(Scenario scenario, FilledBaseline fillerBaseline = null) { var projects = fillerBaseline == null ? scenario.Projects : fillerBaseline.Projects; // TODO: With fillerBaseline use ALL OF the projects var opportunities = projects.Where(p => p is Opportunity).ToArray(); var batches = 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 = projects.Min(p => p.DeliveryDate); var lastDate = 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 + 1; const int weeksBuffer = 3; var delayPenaltyMultiplier = 0.01; // 1% of revenue per week var 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.Threads, 1); //env.Set(GRB.IntParam.NumericFocus, 3); //env.Set(GRB.DoubleParam.TimeLimit, 30); env.Set(GRB.DoubleParam.MIPGap, 0.06); //env.Set(GRB.IntParam.Presolve,2); //env.Set(GRB.IntParam.ScaleFlag, 2); //env.Set(GRB.IntParam.Method, 2); var m = new GRBModel(env); // decide: which batch is when, on which line var varBatchTimeLine1 = m.AddVars(bBc + batchesLine1.Count(), 0, maxDays, GRB.CONTINUOUS, "varBatchTimeLine1"); var varBatchTimeLine2 = m.AddVars(bBc + batchesLine2.Count(), 0, maxDays, GRB.CONTINUOUS, "varBatchTimeLine2"); var varOpportunityIsUsed = m.AddVars(opportunities.Count(), 0, 1, GRB.BINARY, "varOpportunityIsUsed"); var varLineDecision = m.AddVars(bBc, 0, 1, GRB.BINARY, "varLineDecision"); // 0 = Line1, 1 = Line2 //m.Update(); //TODO: Start heuristic //m.Update(); //varMaxedValue[0].Set(GRB.DoubleAttr.Start, 5); // baseline constraint: // we want some opportunities to be used for sure /*if (baseline != null) * { * var mustWinOpportunitites = new List<Opportunity>(); * for (int oi = 0; oi < opportunities.Count(); oi++) * { * if (baseline.Projects.Contains(opportunities[oi])) * { * mustWinOpportunitites.Add((Opportunity)opportunities[oi]); * m.AddConstr(varOpportunityIsUsed[opportunities.IndexOf(opportunities[oi])] == 1); * } * } * * }*/ // line constraints: // if it's a fixed project though, then it must be allocated // 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 < projects.Count(); pi++) { var p = 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]); } } 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); } i_prev = i; } } // scheduling formulation for (int l = 0; l < 2; l++) { var lineVars = l == 0 ? varBatchTimeLine1 : varBatchTimeLine2; 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 - varOpportunityIsUsed[opportunities.IndexOf(o1_exists)]) : new GRBLinExpr(); var s1 = lineVars[bi1]; 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 - varOpportunityIsUsed[opportunities.IndexOf(o2_exists)]) : new GRBLinExpr(); var s2 = lineVars[bi2]; // 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; m.AddConstr(s1 - (s2 + batch2.UsedWorkHours / 24d) >= -maxDays * (decisionVar + opportunityNotUsedSlack)); //TODO: varLineDecisionSlack for both lines batches m.AddConstr(s2 - (s1 + batch1.UsedWorkHours / 24d) >= -maxDays * (1 - decisionVar + opportunityNotUsedSlack)); } } } // 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 // 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 projects) { // if the project is used add the margin if (p is Opportunity) { margin += varOpportunityIsUsed[opportunities.IndexOf(p)] * p.Margin; } else { margin += p.Margin; } // 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 = varBatchTimeLine1[bi] / 7d; } else if (batchesLine2.Contains(b)) { var bi = batchesLine2.IndexOf(b) + bBc; weekValue = varBatchTimeLine2[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 >= varBatchTimeLine1[bi] / 7d - (varLineDecision[bi]) * maxWeek); m.AddConstr(bothLineWeekVar <= varBatchTimeLine1[bi] / 7d + (varLineDecision[bi]) * maxWeek); m.AddConstr(bothLineWeekVar >= varBatchTimeLine2[bi] / 7d - (1 - varLineDecision[bi]) * maxWeek); m.AddConstr(bothLineWeekVar <= varBatchTimeLine2[bi] / 7d + (1 - varLineDecision[bi]) * maxWeek); 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(0, maxWeek, GRB.CONTINUOUS, "weekValueBothLines"); //m.Update(); var wD = weekValue - plannedWeek; m.AddConstr(weekDiffIfUsed >= wD - (1 - varOpportunityIsUsed[opportunities.IndexOf(p)]) * maxWeek); m.AddConstr(weekDiffIfUsed <= wD + (1 - varOpportunityIsUsed[opportunities.IndexOf(p)]) * maxWeek); m.AddConstr(weekDiffIfUsed <= (varOpportunityIsUsed[opportunities.IndexOf(p)]) * maxWeek); m.AddConstr(weekDiffIfUsed >= -(varOpportunityIsUsed[opportunities.IndexOf(p)]) * maxWeek); weekDiff = weekDiffIfUsed; } else { weekDiff = weekValue - plannedWeek; } m.AddConstr(varMaxedValue[pbi] >= weekDiff); m.AddConstr(varMaxedValue[pbi] >= 0); m.AddConstr(varMaxedValue[pbi] <= weekDiff + maxWeek * (varDecisionVar[pbi])); m.AddConstr(varMaxedValue[pbi] <= 0 + maxWeek * (1 - varDecisionVar[pbi])); 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 ? 999999999 : p.Revenue; 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); } previousWeekValue = weekValue; } } m.SetObjective(margin, GRB.MAXIMIZE); //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 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 = varBatchTimeLine1[bBc + batchesLine1.IndexOf(b)].Get(GRB.DoubleAttr.X); } else if (b.Compatibility == Batch.LineCompatibility.Line2) { dayLine2 = varBatchTimeLine2[bBc + batchesLine2.IndexOf(b)].Get(GRB.DoubleAttr.X); } else { var bbi = batchesBothLines.IndexOf(b); var lineDecision = varLineDecision[bbi].Get(GRB.DoubleAttr.X); dayLine1 = varBatchTimeLine1[bbi].Get(GRB.DoubleAttr.X) * (1 - lineDecision); dayLine2 = varBatchTimeLine2[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 && varOpportunityIsUsed[opportunities.IndexOf(p)].Get(GRB.DoubleAttr.X) > 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)); } return(sol); }
public OptimizationResult Solve(long timelimitMiliseconds, EventHandler <ProgressReport> progress, EventHandler <string> consoleProgress) { var sw = Stopwatch.StartNew(); var output = new OptimizationResult { OptimizationInput = input }; var timeWindowIsRelevant = !input.Visits.All(visit => { if (visit.Desired.Length > 0) { return(false); } return(!visit.Unavailable.Any(unavailable => { var(unavailableFrom, unavailableTo) = unavailable; foreach (var(dayFrom, dayTo) in input.Days) { if (IntersectionLength(unavailableFrom, unavailableTo, dayFrom, dayTo) > 0) { return true; } } return false; })); }); // first solve vrp, take result as initial solution. if (!timeWindowIsRelevant) { vrpTimeLimitFactor = 1; } var vrpSolution = input.Visits.Length > 75 ? FakeVRPSolution(input.Santas.Length * input.Days.Length) : new VRPCallbackSolver(input).SolveVRP((int)(timelimitMiliseconds * vrpTimeLimitFactor)); consoleProgress?.Invoke(this, $"vrp needed {sw.ElapsedMilliseconds}ms, remaining {timelimitMiliseconds - sw.ElapsedMilliseconds}"); if (!timeWindowIsRelevant) { BuildResultFromVRP(output, vrpSolution); output.TimeElapsed = sw.ElapsedMilliseconds / 1000; return(output); } timelimitMiliseconds -= sw.ElapsedMilliseconds; using (var env = new GRBEnv($"{DateTime.Now:yy-MM-dd-HH-mm-ss}_gurobi.log")) using (var model = 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] var c = new GRBVar[numberOfRoutes][]; // [santa] visits visit at the end of [way] var desiredDuration = new GRBVar[numberOfRoutes][][]; var unavailableDuration = new GRBVar[numberOfRoutes][][]; var maxRoutes = new GRBVar[numberOfRoutes]; var minRoutes = new GRBVar[numberOfRoutes]; for (int s = 0; s < numberOfRoutes; s++) { v[s] = new GRBVar[visitDurations.Length]; c[s] = new GRBVar[visitDurations.Length]; desiredDuration[s] = new GRBVar[visitDurations.Length][]; unavailableDuration[s] = new GRBVar[visitDurations.Length][]; var(dayStart, dayEnd) = input.Days[s / input.Santas.Length]; var dayDuration = dayEnd - dayStart; for (int i = 0; i < v[s].Length; i++) { v[s][i] = model.AddVar(0, 1, 0.0, GRB.BINARY, GurobiVarName($"v[{s}][{i}]")); c[s][i] = model.AddVar(0, dayDuration, 0, GRB.CONTINUOUS, GurobiVarName($"c[{s}][{i}]")); if (i > 0) { var visit = input.Visits[i - 1]; desiredDuration[s][i] = new GRBVar[visit.Desired.Length]; unavailableDuration[s][i] = new GRBVar[visit.Unavailable.Length]; for (int d = 0; d < visit.Desired.Length; d++) { var ub = Math.Max(0, Math.Min(visit.Duration, visit.Desired[d].to - visit.Desired[d].from)); desiredDuration[s][i][d] = model.AddVar(0, ub, 0, GRB.CONTINUOUS, GurobiVarName($"desiredDuration[{s}][{i}][{d}]")); } for (int u = 0; u < visit.Unavailable.Length; u++) { var ub = Math.Max(0, Math.Min(visit.Duration, visit.Unavailable[u].to - visit.Unavailable[u].from)); unavailableDuration[s][i][u] = model.AddVar(0, ub, 0, GRB.CONTINUOUS, GurobiVarName($"unavailableDuration[{s}][{i}][{u}]")); } } } w[s] = model.AddVars(distances.GetLength(0) * distances.GetLength(1), GRB.BINARY); maxRoutes[s] = model.AddVar(0, dayEnd - dayStart, 0, GRB.CONTINUOUS, GurobiVarName($"santa{s} maxRoute")); minRoutes[s] = model.AddVar(0, dayEnd - dayStart, 0, GRB.CONTINUOUS, GurobiVarName($"santa{s} minRoute")); } #endregion initialize Variables #region add constraints SelfieConstraint(model, numberOfRoutes, w); // visit visited once VisitVisitedOnce(model, numberOfRoutes, v); // breaks BreakHandling(model, numberOfRoutes, v); // number of ways = number of visits + home NumberOfWaysMatchForSanta(model, numberOfRoutes, v, w); // incoming & outgoing constraint IncomingOutgoingGlobal(model, numberOfRoutes, w); IncomingOutgoingSanta(model, numberOfRoutes, v, w); IncomingOutgoingSantaHome(model, numberOfRoutes, w, v); IncreasingC(model, numberOfRoutes, w, c, v); DesiredOverlap(model, numberOfRoutes, v, w, c, desiredDuration); UnavailableOverlap(model, numberOfRoutes, v, w, c, unavailableDuration, true); FillMaxRoute(model, maxRoutes, c, v); FillMinRoutes(model, minRoutes, c, v); MinRouteSmallerThanMaxRoute(model, minRoutes, maxRoutes); // Symmetry breaking constraint if no breaks if (!input.Visits.Any(visit => visit.IsBreak)) { for (int d = 0; d < input.Days.Length; d++) { var dayOffset = d * input.Santas.Length; for (int s = 1; s < input.Santas.Length; s++) { model.AddConstr(maxRoutes[dayOffset + s] - minRoutes[dayOffset + s] <= maxRoutes[dayOffset + s - 1] - minRoutes[dayOffset + s - 1], null); } } } #endregion add constraints // TARGET FUNCTION var totalWayTime = new GRBLinExpr(0); var longestRoute = model.AddVar(0, input.Days.Max(d => d.to - d.from), 0, GRB.CONTINUOUS, "longestRoute"); for (int s = 0; s < numberOfRoutes; s++) { totalWayTime += (maxRoutes[s] - minRoutes[s]); model.AddConstr(longestRoute >= maxRoutes[s] - minRoutes[s], $"longesRouteConstr{s}"); } var desiredSum = new GRBLinExpr(0); var unavailableSum = new GRBLinExpr(0); for (int s = 0; s < numberOfRoutes; s++) { for (int i = 1; i < visitDurations.Length; i++) { var visit = input.Visits[i - 1]; for (int d = 0; d < visit.Desired.Length; d++) { if (!(desiredDuration[s][i][d] is null)) { desiredSum += desiredDuration[s][i][d]; } } for (int u = 0; u < visit.Unavailable.Length; u++) { if (!(unavailableDuration[s][i][u] is null)) { unavailableSum += unavailableDuration[s][i][u]; } } } } LowerBoundTotalWaytime(model, totalWayTime); model.SetObjective( +(12d) * unavailableSum + (4d) * totalWayTime - (2d) * desiredSum + (3d) * longestRoute , GRB.MINIMIZE); model.Parameters.TimeLimit = Math.Max(0, timelimitMiliseconds / 1000); InitializeWithVRPSolution(vrpSolution, numberOfRoutes, model, v, w, c); #if DEBUG model.Write($"{name}_{visitDurations.Length}.mst"); model.Write($"{name}_{visitDurations.Length}.mps"); model.Write($"{name}_{visitDurations.Length}.lp"); #endif model.Optimize(); output.TimeElapsed = sw.ElapsedMilliseconds / 1000; try { if (model.SolCount == 0 && vrpSolution != null) { consoleProgress?.Invoke(this, "No solution found -> try with vrpsolution"); BuildResultFromVRP(output, vrpSolution); return(output); } BuildResult(output, numberOfRoutes, w, c); consoleProgress?.Invoke(this, $"longestRoute: {longestRoute.X}"); consoleProgress?.Invoke(this, $"totalWayTime: {totalWayTime.Value}"); consoleProgress?.Invoke(this, $"DesiredDuration: {desiredSum.Value}"); consoleProgress?.Invoke(this, $"UnavailableDuration: {unavailableSum.Value}"); for (int s = 0; s < numberOfRoutes; s++) { consoleProgress?.Invoke(this, $"maxRoutes[{s}]: {maxRoutes[s].X}, {minRoutes[s].X} , ->{maxRoutes[s].X - minRoutes[s].X}"); for (int visitIndex = 0; visitIndex < visitDurations.Length; visitIndex++) { consoleProgress?.Invoke(this, $"c[{s}][{visitIndex}] ({v[s][visitIndex].X}): {c[s][visitIndex].X}"); } } } catch (Exception e) { consoleProgress?.Invoke(this, $"ERROR: {e.Message}"); output.Routes = new Route[0]; } } return(output); }
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 SubModelOutputs Build_Model( InputData inputData, string outputFolder ) { try { // Create an empty environment, set options and start GRBEnv env = new GRBEnv(true); env.Set("LogFile", "LogFileGurobiModel.log"); env.Start(); int T = 4; List <T_param> Tlist2 = inputData.TList.FindAll(tl => tl.T >= 2); List <T_param> Tlist3 = inputData.TList.FindAll(tl => tl.T >= 3); // Create empty Gurobi model GRBModel gModel = new GRBModel(env); // Create an empty linear expression object. //Parameters and variables will be added and then used to add model components //(Objective Function and Constraints). GRBLinExpr expr1 = 0.0; GRBLinExpr expr2 = 0.0; // Crear la variables GRBVar[] Make = gModel.AddVars(inputData.ProdList.Count * Tlist2.Count * inputData.ScenList.Count, GRB.CONTINUOUS); GRBVar[] Inv = gModel.AddVars(inputData.ProdList.Count * Tlist2.Count * inputData.ScenList.Count, GRB.CONTINUOUS); GRBVar[] Sell = gModel.AddVars(inputData.ProdList.Count * Tlist2.Count * inputData.ScenList.Count, GRB.CONTINUOUS); //MAKE VARNAME inputData.ProdList.ForEach(pl => { Tlist2.ForEach(tl => { inputData.ScenList.ForEach(sl => { int ixP = inputData.ProdList.IndexOf(pl); int ixT = Tlist2.IndexOf(tl); int ixS = inputData.ScenList.IndexOf(sl); int ix = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count); Make[ix].VarName = "MAKE_PROD: " + pl.PROD + " T: " + tl.T + " SCEN: " + sl.SCEN; }); }); }); //INV VARNAME inputData.ProdList.ForEach(pl => { Tlist2.ForEach(tl => { inputData.ScenList.ForEach(sl => { int ixP = inputData.ProdList.IndexOf(pl); int ixT = Tlist2.IndexOf(tl); int ixS = inputData.ScenList.IndexOf(sl); int ix = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count); Inv[ix].VarName = "INV_PROD: " + pl.PROD + " T: " + tl.T + " SCEN: " + sl.SCEN; }); }); }); //SELL VARNAME inputData.ProdList.ForEach(pl => { Tlist2.ForEach(tl => { inputData.ScenList.ForEach(sl => { int ixP = inputData.ProdList.IndexOf(pl); int ixT = Tlist2.IndexOf(tl); int ixS = inputData.ScenList.IndexOf(sl); int ix = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count); Sell[ix].VarName = "SELL_PROD: " + pl.PROD + " T: " + tl.T + " SCEN: " + sl.SCEN; }); }); }); //MAKE => 0 (constrain) //GRB.CONTINUOUS for (int a = 0; a < Make.Length; a++) { expr1.Clear(); expr1.AddTerm(1, Make[a]); gModel.AddConstr(expr1, GRB.GREATER_EQUAL, 0, ">=0"); } //INV => 0 (constrain) for (int a = 0; a < Inv.Length; a++) { expr1.Clear(); expr1.AddTerm(1, Inv[a]); gModel.AddConstr(expr1, GRB.GREATER_EQUAL, 0, ">=0"); } //SELL => 0 (constrain) for (int a = 0; a < Sell.Length; a++) { expr1.Clear(); expr1.AddTerm(1, Sell[a]); gModel.AddConstr(expr1, GRB.GREATER_EQUAL, 0, ">=0"); } //SELL <= market[p,t] expr1.Clear(); inputData.ProdList.ForEach(pl => { Tlist2.ForEach(tl => { inputData.ScenList.ForEach(sl => { double market = inputData .MarketList .Find(ml => ml.PROD.Equals(pl.PROD) && ml.T.Equals(tl.T)).MARKET; int ixP = inputData.ProdList.IndexOf(pl); int ixT = Tlist2.IndexOf(tl); int ixS = inputData.ScenList.IndexOf(sl); int index = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count); expr1.Clear(); expr1.AddTerm(1, Sell[index]); gModel.AddConstr(expr1, GRB.LESS_EQUAL, market, "<=Market"); }); }); }); //Construir funcion objetivo //maximize Stage2_Profit: // sum {s in SCEN} prob[s] * // sum {p in PROD, t in 2..T} (revenue[p,t,s]*Sell[p,t,s] - // prodcost[p]*Make[p,t,s] - invcost[p]*Inv[p,t,s]); expr1.Clear(); inputData.ScenList.ForEach(s => { double prob = inputData.ProbList.Find(x => x.SCEN.Equals(s.SCEN)).PROB; inputData.ProdList.ForEach(p => { Tlist2.ForEach(tl => { //SELL double revenue = inputData .RevenueList .Find(r => r.PROD.Equals(p.PROD) && r.T.Equals(tl.T) && r.SCEN.Equals(s.SCEN) ).REVENUE; double prodCost = inputData .ProdCostList .Find(pc => pc.PROD.Equals(p.PROD) ).PRODCOST; double invCost = inputData .InvCostList .Find(ic => ic.PROD.Equals(p.PROD) ).INVCOST; int ixP = inputData.ProdList.IndexOf(p); int ixT = Tlist2.IndexOf(tl); int ixS = inputData.ScenList.IndexOf(s); int indexVar = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count); expr1.AddTerm(prob * revenue, Sell[indexVar]); expr1.AddTerm(-1 * prob * prodCost, Make[indexVar]); expr1.AddTerm(-1 * prob * invCost, Inv[indexVar]); }); }); }); //Insertar funcion objetivo gModel.SetObjective(expr1, GRB.MAXIMIZE); //Insertar Restricciones //subject to Time {t in 2..T, s in SCEN}: //sum {p in PROD} (1/rate[p]) * Make[p,t,s] <= avail[t]; expr1.Clear(); Tlist2.ForEach(tl => { inputData.ScenList.ForEach(sl => { inputData.ProdList.ForEach(pl => { double rate = 1 / inputData.RateList.Find(rl => rl.PROD.Equals(pl.PROD)).RATE; int ixP = inputData.ProdList.IndexOf(pl); int ixT = Tlist2.IndexOf(tl); int ixS = inputData.ScenList.IndexOf(sl); int ixMake = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count); expr1.AddTerm(rate, Make[ixMake]); }); double avail = inputData.AvailList.Find(al => al.T.Equals(tl.T)).AVAIL; gModel.AddConstr(expr1, GRB.LESS_EQUAL, avail, "TIME_" + tl.T + "_" + sl.SCEN); }); }); //subject to Balance2 { p in PROD, s in SCEN}: //Make[p, 2, s] + inv1[p] = Sell[p, 2, s] + Inv[p, 2, s]; //2 => index T => 0 expr1.Clear(); inputData.ProdList.ForEach(pl => { inputData.ScenList.ForEach(sl => { int ixP = inputData.ProdList.IndexOf(pl); int ixT = 0; int ixS = inputData.ScenList.IndexOf(sl); int ix = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count); double inv1 = subModelParams.inv1.Find(il => il.PROD.Equals(pl.PROD)).INV0; expr1.Clear(); expr2.Clear(); //como sumar un param ???? expr1.AddTerm(1, Make[ix]); //expr1.AddTerm(inv1, null); ???? como??? // Se despeja vars & params expr1.AddTerm(-1, Sell[ix]); expr1.AddTerm(-1, Inv[ix]); gModel.AddConstr(expr1, GRB.EQUAL, inv1, "BALANCE2_" + pl.PROD + "_" + sl.SCEN); }); }); //subject to Balance { p in PROD, t in 3..T, s in SCEN}: //Make[p, t, s] + Inv[p, t - 1, s] = Sell[p, t, s] + Inv[p, t, s]; inputData.ProdList.ForEach(pl => { Tlist3.ForEach(tl => { inputData.ScenList.ForEach(sl => { int ixP = inputData.ProdList.IndexOf(pl); int ixT = Tlist2.IndexOf(tl); int ixS = inputData.ScenList.IndexOf(sl); int ix = ixVar.getIx3(ixP, ixT, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count); int ix2 = ixVar.getIx3(ixP, ixT - 1, ixS, inputData.ProdList.Count, Tlist2.Count, inputData.ScenList.Count); expr1.Clear(); expr2.Clear(); expr1.AddTerm(1, Make[ix]); expr1.AddTerm(1, Inv[ix2]); expr2.AddTerm(1, Sell[ix]); expr2.AddTerm(1, Inv[ix]); gModel.AddConstr(expr1, GRB.EQUAL, expr2, "SUBJECT TO BALANCE"); }); }); }); //carpeta donde se expande el modelo gModel.Write(outputFolder + "Submodel_Model.lp"); // RESOLVER EL MODELO try { Console.WriteLine("Solving the sub model with gurobi.."); gModel.Optimize(); if (gModel.Status == 2) { for (int m = 0; m < Make.Length; m++) { Console.WriteLine("Make Var: " + Make[m].VarName + " = " + Make[m].X); } for (int m = 0; m < Inv.Length; m++) { Console.WriteLine("Inv Var: " + Inv[m].VarName + " = " + Inv[m].X); } for (int m = 0; m < Sell.Length; m++) { Console.WriteLine("Sell Var: " + Sell[m].VarName + " = " + Sell[m].X); } } SubModelOutputs smo = new SubModelOutputs() { make = Make, sell = Sell, inv = Inv, stage2Profit = gModel.ObjVal, gModel = gModel }; //gModel.Dispose(); //env.Dispose(); return(smo); } catch { Console.WriteLine("ERROR SOLVING THE MODEL"); } gModel.Dispose(); env.Dispose(); } catch (GRBException ex) { Console.WriteLine("Error code: " + ex.ErrorCode + ". " + ex.Message); } return(new SubModelOutputs()); }
public MasterModelOutputs buildModel( InputData inputData, int nCUT, MasterModelParameters masterModelParameters, string outputFolder ) { try { // Create an empty environment, set options and start GRBEnv env = new GRBEnv(true); env.Set("LogFile", "LogFileGurobiModel.log"); env.Start(); int T = 4; List <T_param> Tlist2 = inputData.TList.FindAll(tl => tl.T >= 2); List <T_param> Tlist3 = inputData.TList.FindAll(tl => tl.T >= 3); // Create empty Gurobi model GRBModel gModel = new GRBModel(env); // Create an empty linear expression object. //Parameters and variables will be added and then used to add model components //(Objective Function and Constraints). GRBLinExpr expr1 = 0.0; GRBLinExpr expr2 = 0.0; // Crear la variables GRBVar[] Make1 = gModel.AddVars(inputData.ProdList.Count, GRB.CONTINUOUS); GRBVar[] Inv1 = gModel.AddVars(inputData.ProdList.Count, GRB.CONTINUOUS); GRBVar[] Sell1 = gModel.AddVars(inputData.ProdList.Count, GRB.CONTINUOUS); //MAKE1 VARNAME inputData.ProdList.ForEach(pl => { int ixP = inputData.ProdList.IndexOf(pl); Make1[ixP].VarName = "MAKE1_Prod: " + pl.PROD; }); //INV1 VARNAME inputData.ProdList.ForEach(pl => { int ixP = inputData.ProdList.IndexOf(pl); Inv1[ixP].VarName = "INV1_Prod: " + pl.PROD; }); //MAKE1 VARNAME inputData.ProdList.ForEach(pl => { int ixP = inputData.ProdList.IndexOf(pl); Sell1[ixP].VarName = "SELL1_Prod: " + pl.PROD; }); //MAKE1 => 0 (constrain) //GRB.CONTINUOUS for (int a = 0; a < Make1.Length; a++) { expr1.Clear(); expr1.AddTerm(1, Make1[a]); gModel.AddConstr(expr1, GRB.GREATER_EQUAL, 0, ">=0"); } //INV1 => 0 (constrain) for (int a = 0; a < Inv1.Length; a++) { expr1.Clear(); expr1.AddTerm(1, Inv1[a]); gModel.AddConstr(expr1, GRB.GREATER_EQUAL, 0, ">=0"); } //SELL1 => 0 (constrain) for (int a = 0; a < Sell1.Length; a++) { expr1.Clear(); expr1.AddTerm(1, Sell1[a]); gModel.AddConstr(expr1, GRB.GREATER_EQUAL, 0, ">=0"); } //SELL1 <= market[p,1] expr1.Clear(); inputData.ProdList.ForEach(pl => { double market = inputData .MarketList .Find(ml => ml.PROD.Equals(pl.PROD) && ml.T.Equals(1)).MARKET; int ixP = inputData.ProdList.IndexOf(pl); expr1.Clear(); expr1.AddTerm(1, Sell1[ixP]); gModel.AddConstr(expr1, GRB.LESS_EQUAL, market, "<=Market"); }); GRBVar Min_Stage2_Profit = gModel.AddVar(double.MinValue, double.MaxValue, masterModelParameters.Min_Stage2_Profit, GRB.CONTINUOUS, "Min_Stage2_Profit"); //Funcion objetivo //maximize Expected_Profit: //sum { s in SCEN} //prob[s] * //sum { p in PROD} (revenue[p, 1, s] * Sell1[p] - //prodcost[p] * Make1[p] - invcost[p] * Inv1[p]) + //Min_Stage2_Profit; expr1.Clear(); inputData.ScenList.ForEach(sl => { double prob = inputData.ProbList.Find(x => x.SCEN.Equals(sl.SCEN)).PROB; inputData.ProdList.ForEach(pl => { double revenue = inputData .RevenueList .Find(rl => rl.PROD.Equals(pl.PROD) && rl.T.Equals(1) && rl.SCEN.Equals(sl.SCEN)) .REVENUE; int ixP = inputData.ProdList.IndexOf(pl); double invcost = inputData.InvCostList.Find(inv => inv.PROD.Equals(pl.PROD)).INVCOST; double prodcost = inputData.ProdCostList.Find(inv => inv.PROD.Equals(pl.PROD)).PRODCOST; expr1.AddTerm(prob * revenue, Sell1[ixP]); expr1.AddTerm(-prob * prodcost, Make1[ixP]); expr1.AddTerm(-prob * invcost, Inv1[ixP]); expr1.AddTerm(1, Min_Stage2_Profit); }); }); //Insertar funcion objetivo gModel.SetObjective(expr1, GRB.MAXIMIZE); //subj to Cut_Defn {k in 1..nCUT}: KE ESTA PASANDO // Min_Stage2_Profit <= // sum { t in 2..T, s in SCEN} // time_price[t, s, k] * avail[t] + // sum { p in PROD, s in SCEN} // bal2_price[p, s, k] * (-Inv1[p]) + // sum { p in PROD, t in 2..T, s in SCEN} // sell_lim_price[p, t, s, k] * market[p, t]; expr1.Clear(); double sumPriceAvail = 0; double sumPriceMarket = 0; expr1.AddTerm(1, Min_Stage2_Profit); for (int k = 1; k <= nCUT; k++) { // sum { t in 2..T, s in SCEN} // time_price[t, s, k] * avail[t] + Tlist2.ForEach(tl => { inputData.ScenList.ForEach(sl => { double timePrice = masterModelParameters.timePriceList.Find(x => x.T.Equals(tl.T) && x.SCEN.Equals(sl.SCEN) && x.nCUT.Equals(k)).TIMEPRICE; double avail = inputData.AvailList.Find(al => al.T.Equals(tl.T)).AVAIL; sumPriceAvail += timePrice * avail; }); }); // sum { p in PROD, t in 2..T, s in SCEN} // sell_lim_price[p, t, s, k] * market[p, t]; inputData.ProdList.ForEach(pl => { Tlist2.ForEach(tl => { inputData.ScenList.ForEach(sl => { double sellLimPrice = masterModelParameters.sellLimPriceList.Find(slpl => slpl.PROD.Equals(pl.PROD) && slpl.T.Equals(tl.T) && slpl.SCEN.Equals(sl.SCEN) && slpl.nCUT.Equals(k)).SELLLIMPRICE; double market = inputData.MarketList.Find(ml => ml.PROD.Equals(pl.PROD) && ml.T.Equals(tl.T)).MARKET; sumPriceMarket += sellLimPrice * market; }); }); }); // sum { p in PROD, s in SCEN} // bal2_price[p, s, k] * (-Inv1[p]) + inputData.ProdList.ForEach(pl => { inputData.ScenList.ForEach(sl => { double bal2Price = masterModelParameters.balance2PriceList.Find(bp => bp.PROD.Equals(pl.PROD) && bp.SCEN.Equals(sl.SCEN) && bp.nCUT.Equals(k)).BALANCE2PRICE; int ixP = inputData.ProdList.IndexOf(pl); expr1.AddTerm(bal2Price, Inv1[ixP]); }); }); } gModel.AddConstr(expr1, GRB.LESS_EQUAL, sumPriceAvail + sumPriceMarket, "Cut_Defn"); //subject to Time1: //sum { p in PROD} (1 / rate[p]) * Make1[p] <= avail[1]; expr1.Clear(); inputData.ProdList.ForEach(pl => { double rate = 1 / inputData.RateList.Find(rl => rl.PROD.Equals(pl.PROD)).RATE; double avail = inputData.AvailList.Find(al => al.T.Equals(1)).AVAIL; double rateAvail = avail / rate; int ixP = inputData.ProdList.IndexOf(pl); gModel.AddConstr(Make1[ixP], GRB.GREATER_EQUAL, rateAvail, "TIME1"); }); //subject to Balance1 { p in PROD}: //Make1[p] + inv0[p] = Sell1[p] + Inv1[p]; expr1.Clear(); inputData.ProdList.ForEach(pl => { expr1.Clear(); int ixP = inputData.ProdList.IndexOf(pl); expr1.AddTerm(1, Sell1[ixP]); expr1.AddTerm(1, Inv1[ixP]); expr1.AddTerm(-1, Make1[ixP]); double inv0 = inputData.Inv0List.Find(il => il.PROD.Equals(pl.PROD)).INV0; gModel.AddConstr(inv0, GRB.EQUAL, expr1, "Balance1"); }); //carpeta donde se expande el modelo master gModel.Write(outputFolder + "Master_Model.lp"); // RESOLVER EL MODELO try { Console.WriteLine("Solving the master model with gurobi.."); gModel.Optimize(); if (gModel.Status == 2) { for (int m = 0; m < Make1.Length; m++) { Console.WriteLine("Make1 Var: " + Make1[m].VarName + " = " + Make1[m].X); } for (int m = 0; m < Inv1.Length; m++) { Console.WriteLine("Inv1 Var: " + Inv1[m].VarName + " = " + Inv1[m].X); } for (int m = 0; m < Sell1.Length; m++) { Console.WriteLine("Sell Var: " + Sell1[m].VarName + " = " + Sell1[m].X); } } gModel.Dispose(); env.Dispose(); return(new MasterModelOutputs() { make1 = Make1, sell1 = Sell1, inv1 = Inv1, expectedProfit = gModel.ObjVal, gModel = gModel }); } catch { Console.WriteLine("ERROR SOLVING THE MODEL"); } gModel.Dispose(); env.Dispose(); } catch (GRBException ex) { Console.WriteLine("Error code: " + ex.ErrorCode + ". " + ex.Message); } return(new MasterModelOutputs()); }
public static GRBVar[] AddVars(this GRBModel _m, int _count, double lb, double ub, char type, string _prefix = null) { return(_m.AddVars(Enumerable.Repeat(lb, _count).ToArray(), Enumerable.Repeat(ub, _count).ToArray(), null, Enumerable.Repeat(type, _count).ToArray(), _prefix == null ? null : Enumerable.Range(0, _count).Select(i => $"{_prefix}[{i}]").ToArray() )); }
private void CreateBatchSizeVariables() { variables.batch_size = model.AddVars(num_periods, GRB.INTEGER); }
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 override Schedule Generate(Scenario scenario, FilledBaseline baseline = null) { var batches = scenario.Projects.SelectMany(p => p.Batches).OrderBy(b => b.Compatibility).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. int maxWeek = (lastDate - earliestDate).Days / 7; // 0 to 200 const int weeksBuffer = 3; var delayPenaltyMultiplier = 0.01; // 1% of revenue per week var interestPenaltyMultiplier = (0.045 / 52.14); // 4.5% / 52.14 * (revenue – margin) var env = new GRBEnv(); env.Set(GRB.IntParam.LogToConsole, 1); //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 // TODO: Batch can be over two weeks var varBatchWeekLine1 = m.AddVars(batchesBothLines.Count() + batchesLine1.Count(), maxWeek, 0, 1, GRB.BINARY, "batchWeekLine1"); var varBatchWeekLine2 = m.AddVars(batchesBothLines.Count() + batchesLine2.Count(), maxWeek, 0, 1, GRB.BINARY, "batchWeekLine2"); m.Update(); // 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 ? varBatchWeekLine1 : varBatchWeekLine2; for (int bi = bBc; bi < line.GetLength(0); bi++) { var batchTotal = new GRBLinExpr(); for (int w = 0; w < maxWeek; w++) { batchTotal += line[bi, w]; } 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 w = 0; w < maxWeek; w++) { batchTotal += varBatchWeekLine1[bi, w]; batchTotal += varBatchWeekLine2[bi, w]; } 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"); } } // 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? var varLineDecision = m.AddVars(scenario.Projects.Count(), 0, 1, GRB.BINARY, "varLineDecision"); m.Update(); 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; } var sumBatchLine1 = new GRBLinExpr(); var sumBatchLine2 = new GRBLinExpr(); int i = batches.IndexOf(p.Batches.First()); for (int j = 0; j < p.Batches.Count(); j++) { if (p.Batches[j].Compatibility != Batch.LineCompatibility.Both) { continue; } for (int w = 0; w < maxWeek; w++) { sumBatchLine1 += varBatchWeekLine1[i + j, w]; sumBatchLine2 += varBatchWeekLine2[i + j, w]; } } m.AddConstr(sumBatchLine1 <= (1 - varLineDecision[pi]) * GRB.INFINITY); m.AddConstr(sumBatchLine2 <= varLineDecision[pi] * GRB.INFINITY); } // on each line the total of a week must not exceed 24*7 for (int l = 0; l < 2; l++) { var lineVars = l == 0 ? varBatchWeekLine1 : varBatchWeekLine2; var line = l == 0 ? batchesLine1 : batchesLine2; int bBC = batchesBothLines.Count(); for (int w = 0; w < maxWeek; w++) { var weekTotal = new GRBLinExpr(); for (int b = 0; b < lineVars.GetLength(0); b++) { var batch = b < bBC ? batchesBothLines[b] : line[b - bBC]; weekTotal += lineVars[b, w] * batch.UsedWorkHours; /*var test = new GRBLinExpr(); * test += (lineVars[b] == w) * 0.1; * (l[b] - w) * batch.UsedWorkHours*/ } m.AddConstr(weekTotal <= 24 * 7); } } // 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 w = 0; w < maxWeek; w++) { batchTotal += varBatchWeekLine1[bIndex, w]; } } else if (b.Compatibility == Batch.LineCompatibility.Line2) { var bIndex = bBc + batchesLine2.IndexOf(b); for (int w = 0; w < maxWeek; w++) { batchTotal += varBatchWeekLine2[bIndex, w]; } } else { var bIndex = batchesBothLines.IndexOf(b); for (int w = 0; w < maxWeek; w++) { batchTotal += varBatchWeekLine1[bIndex, w]; batchTotal += varBatchWeekLine2[bIndex, w]; } } // the sum of this batch over all weeks (0 or 1) has to be the same as the sum of the previous one if (bi > 0) { m.AddConstr(previousBatchTotal == batchTotal); } previousBatchTotal = batchTotal; allBatches.Add(batchTotal); } totalBatchesOfProject.Add(p, allBatches); } // DEPRECATED: penalty/interest term adds this constraint with slack // in-between batches of the same project, 3 weeks distance should exist, otherwise there will be a penalty /*foreach (var p in scenario.Projects) * { * var bCompatibility = p.Batches.First().Compatibility; * * // for all batches of this project make sure that the previous one is at least (3 + 1) weeks away * // in other words: the total of batches within (3 + 1) weeks must be 4 at least. * for (int w = 0; w < maxWeek - weeksBuffer; w++) * { * var batchTotalOver4Weeks = new GRBLinExpr(); * // sum all batches over a 4 week period * for (int i = 0; i <= weeksBuffer; i++) * { * foreach (var b in p.Batches) * { * if (bCompatibility == Batch.LineCompatibility.Line1) * { * batchTotalOver4Weeks += varBatchWeekLine1[bBc + batchesLine1.IndexOf(b), w + i]; * } * else if (bCompatibility == Batch.LineCompatibility.Line2) * { * batchTotalOver4Weeks += varBatchWeekLine2[bBc + batchesLine2.IndexOf(b), w + i]; * } * else * { * var bIndex = batchesBothLines.IndexOf(b); * batchTotalOver4Weeks += varBatchWeekLine1[bIndex, w + i]; * batchTotalOver4Weeks += varBatchWeekLine2[bIndex, w + i]; * } * } * } * m.AddConstr(batchTotalOver4Weeks <= 1); * } * }*/ // 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 // Maximize the margin (including delay and interest penalties) and the workload // TODO: Only first one important? no delay otherwise? var margin = new GRBLinExpr(); foreach (var p in scenario.Projects) { // if the project is used add the margin margin += totalBatchesOfProject[p].First() * p.Margin; // deduct the delay penalty for each batch. int startWeekOfProject = (p.DeliveryDate - earliestDate).Days / 7; 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 bi = 0; bi < p.Batches.Count(); bi++) { var b = p.Batches[bi]; // compare the minimal batch time (3 + 1 weeks) to the actual delivery time var weekValue = new GRBLinExpr(); if (b.Compatibility == Batch.LineCompatibility.Line1) { var bIndex = bBc + batchesLine1.IndexOf(b); for (int w = 0; w < maxWeek; w++) { weekValue += varBatchWeekLine1[bIndex, w] * w; } } else if (b.Compatibility == Batch.LineCompatibility.Line2) { var bIndex = bBc + batchesLine2.IndexOf(b); for (int w = 0; w < maxWeek; w++) { weekValue += varBatchWeekLine2[bIndex, w] * w; } } else { var bIndex = batchesBothLines.IndexOf(b); for (int w = 0; w < maxWeek; w++) { weekValue += varBatchWeekLine1[bIndex, w] * w; weekValue += varBatchWeekLine2[bIndex, w] * w; } } if (bi < p.Batches.Count() - 1) { // for positive difference add delay penalty, for negative difference add interest penalty // var = max(0, x) // var * delay // (x - var) * interest var plannedWeek = startWeekOfProject + bi * (weeksBuffer + 1); var weekDiff = weekValue - plannedWeek * totalBatchesOfProject[p].First(); // here we multiply the planned week with the (0/1)-allocation-indicator to avoid penalties when the project is not assigned (and therefore weekValue = 0) m.AddConstr(varMaxedValue[bi] >= weekDiff); m.AddConstr(varMaxedValue[bi] >= 0); m.AddConstr(varMaxedValue[bi] <= weekDiff + maxWeek * (varDecisionVar[bi])); m.AddConstr(varMaxedValue[bi] <= 0 + maxWeek * (1 - varDecisionVar[bi])); double firstBatchImportance = bi == 0 ? 1 : 0.2; // mainly the first batch is important, the rest is meh margin += varMaxedValue[bi] * delayPenaltyMultiplier * firstBatchImportance; margin += (weekDiff - varMaxedValue[bi]) * interestPenaltyMultiplier * firstBatchImportance; } // constraint: batches of a project have to be in succession, i.e. batch2 can't come after batch3 chronologically if (bi > 0) { m.AddConstr(weekValue - previousWeekValue >= 0); } previousWeekValue = weekValue; } } m.SetObjective(margin, GRB.MAXIMIZE); m.Update(); m.Optimize(); //env.Set(GRB.IntParam.IISMethod, 0); // makes IIS computation fast but potentially inaccurate //m.ComputeIIS(); //m.Write("ilp.ilp"); // build the solution from the optimization var sol = new Schedule(); foreach (var p in scenario.Projects) { List <Schedule.BatchAllocation> allocatedBatches = new List <Schedule.BatchAllocation>(); for (int bi = 0; bi < p.Batches.Count(); bi++) { var b = p.Batches[bi]; // figure out on which week and which line the batch is allocated int weekLine1 = 0; int weekLine2 = 0; if (b.Compatibility == Batch.LineCompatibility.Line1) { for (int w = 1; w <= maxWeek; w++) { weekLine1 += (int)varBatchWeekLine1[bBc + batchesLine1.IndexOf(b), w - 1].Get(GRB.DoubleAttr.X) * w; } } else if (b.Compatibility == Batch.LineCompatibility.Line2) { for (int w = 1; w <= maxWeek; w++) { weekLine2 += (int)varBatchWeekLine2[bBc + batchesLine2.IndexOf(b), w - 1].Get(GRB.DoubleAttr.X) * w; } } else { for (int w = 1; w <= maxWeek; w++) { weekLine1 += (int)varBatchWeekLine1[batchesBothLines.IndexOf(b), w - 1].Get(GRB.DoubleAttr.X) * w; weekLine2 += (int)varBatchWeekLine2[batchesBothLines.IndexOf(b), w - 1].Get(GRB.DoubleAttr.X) * w; } } if (weekLine1 > 0 && weekLine2 > 0) { throw new InvalidOperationException(); } var alloc = Schedule.LineAllocation.None; if (weekLine1 > 0) { alloc = Schedule.LineAllocation.Line1; } if (weekLine2 > 0) { alloc = Schedule.LineAllocation.Line2; } allocatedBatches.Add(new Schedule.BatchAllocation(b, alloc, earliestDate.AddDays(weekLine1 + weekLine2 - 1))); } sol.Add(new Schedule.ProjectAllocation(p, allocatedBatches)); } return(sol); }
dense_optimize(GRBEnv env, int rows, int cols, double[] c, // linear portion of objective function double[,] Q, // quadratic portion of objective function double[,] A, // constraint matrix char[] sense, // constraint senses double[] rhs, // RHS vector double[] lb, // variable lower bounds double[] ub, // variable upper bounds char[] vtype, // variable types (continuous, binary, etc.) double[] solution) { bool success = false; try { GRBModel model = new GRBModel(env); // Add variables to the model GRBVar[] vars = model.AddVars(lb, ub, null, vtype, null); // Populate A matrix for (int i = 0; i < rows; i++) { GRBLinExpr expr = new GRBLinExpr(); for (int j = 0; j < cols; j++) { if (A[i, j] != 0) { expr.AddTerm(A[i, j], vars[j]); // Note: '+=' would be much slower } } model.AddConstr(expr, sense[i], rhs[i], ""); } // Populate objective GRBQuadExpr obj = new GRBQuadExpr(); if (Q != null) { for (int i = 0; i < cols; i++) { for (int j = 0; j < cols; j++) { if (Q[i, j] != 0) { obj.AddTerm(Q[i, j], vars[i], vars[j]); // Note: '+=' would be much slower } } } for (int j = 0; j < cols; j++) { if (c[j] != 0) { obj.AddTerm(c[j], vars[j]); // Note: '+=' would be much slower } } model.SetObjective(obj); } // Solve model model.Optimize(); // Extract solution if (model.Status == GRB.Status.OPTIMAL) { success = true; for (int j = 0; j < cols; j++) { solution[j] = vars[j].X; } } model.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } return(success); }
static void Main(string[] args) { GRBEnv env = new GRBEnv("TJLinearCharacter.log"); GRBModel model = new GRBModel(env); //declare the iv variables and key variables GRBVar[] keyvar = model.AddVars(80, GRB.BINARY); //declare the assignment variables of key variables GRBVar[] ivvar = model.AddVars(80, GRB.BINARY); //declare the assignment variables of iv variables GRBVar[] kvf = model.AddVars(80, GRB.BINARY); //declare the flag variables of key variables GRBVar[] vvf = model.AddVars(80, GRB.BINARY); //declare the flag variables of iv variables GRBVar[] Uvar = model.AddVars(8000, GRB.BINARY); //interval assignment variables used to long XOR expression into short ones y=k1+k2+k3+k4--> u1=k1+k2, u2=k3+k4, y=u1+u2 GRBVar[] Vvar = model.AddVars(8000, GRB.INTEGER); //interval variables GRBVar[] Wvar = model.AddVars(8000, GRB.BINARY); //interval variables GRBVar[] UFvar = model.AddVars(8000, GRB.BINARY); //UFvar[i] is the flag variables corresponding to Uvar[i] GRBVar[] NUvar = model.AddVars(8000, GRB.BINARY); //NUvar[i]= 1-Uvar[i] GRBVar[] NUFvar = model.AddVars(8000, GRB.BINARY); //NUFvar[i]= 1-UFvar[i] GRBVar[] Consvar = model.AddVars(8000, GRB.BINARY); //constant variables GRBVar[] bvar = model.AddVars(8000, GRB.BINARY); //b variables int i, j, k; int loc0 = 0, loc1 = 0, loc2 = 0, loc3 = 0, loc4 = 0, locb = 0; int locf = 0; int con = 0; // name all the variables used in this MILP model for (i = 0; i < keyvar.Length; i++) { keyvar[i].VarName = "k" + i.ToString(); ivvar[i].VarName = "v" + i.ToString(); kvf[i].VarName = "kf" + i.ToString(); vvf[i].VarName = "vf" + i.ToString(); } for (i = 0; i < Uvar.Length; i++) { Uvar[i].VarName = "U" + i.ToString(); Wvar[i].VarName = "W" + i.ToString(); UFvar[i].VarName = "UF" + i.ToString(); Vvar[i].VarName = "V" + i.ToString(); NUvar[i].VarName = "NU" + i.ToString(); NUFvar[i].VarName = "NUF" + i.ToString(); bvar[i].VarName = "b" + i.ToString(); Consvar[i].VarName = "cons" + i.ToString(); } UInt32[, ,] ConS = new UInt32[1000, 200, 6];//used to store the conditions derived to control the propagation of difference int[] conlen = new int[1000]; int[] consflag = new int[1000]; int[] rec_loc1 = new int[1000]; int[] rec_locf = new int[1000]; //the number of the conditions int consnum = 652; int[] loc = new int[2]; int[] locw = new int[1]; int[] condiassig = new int[consnum]; int[] condiflag = new int[consnum]; GRBLinExpr Tar = new GRBLinExpr();//declare the target linear expression, which is used as the objective function List <int> indlist = new List <int>() { }; List <GRBVar> Varlist = new List <GRBVar>() { }; List <GRBVar> VarlistCopy = new List <GRBVar>() { }; List <GRBVar> VarFlaglist = new List <GRBVar>() { }; //List<GRBVar> VarFlaglistCopy = new List<GRBVar>() { }; StreamWriter sw = new StreamWriter("FinalCons.txt"); //the index of cube variables List <int> cube = new List <int>() { 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78 }; //set the state of cube variables to \delta for (i = 0; i < cube.Count; i++) { model.AddConstr(vvf[cube[i]] == 1, "iniiv" + (cube[i]).ToString()); } //set the contraints between an assigment variable and the corresponding flag variable for (i = 0; i < 80; i++) { model.AddConstr(keyvar[i] <= 1 - kvf[i], "keyflagrel"); model.AddConstr(ivvar[i] <= 1 - vvf[i], "ivflagrel"); } model.Update(); //read the derived constraints from the file ReadCondition(ConS, conlen, consflag); Console.Write("ReadConditionDone\n"); //model each condition for (i = 0; i < consnum; i++) { loc[0] = loc1; loc[1] = locf; VarFlaglist.Clear(); Varlist.Clear(); //linearize a condition and return a list of involved variables. //In this condition, for condition f, it would linearize it and would return the assignment/flag variable of each monomial in f; //In paticular, Uvar[0],Uvar[1],...,Uvar[m-1] are the assignment variables of the linearized monomials //UFvar[0],UFvar[1],...,UFvar[m-1] are the flag variables of the linearized monomials //For eaxmple, for a condition f=k1+k2*k3+k4, it can be linearized as f=u1+u2+u3 where u2=k2k3. //Then, Varlist[0],Varlist[1],Varlist[2] are assignment variables of u1,u2,u3 //and VarFlaglist[0],VarFlaglist[1],...,VarFlaglist[2] are the flag variables of u1,u2,u3 Varlist = LinearConstrain(model, Uvar, UFvar, ConS, conlen, i, keyvar, ivvar, loc, kvf, vvf, Wvar, locw, VarFlaglist); loc1 = loc[0]; locf = loc[1]; //here a condition f is linearized and so it is the XOR of several variables. //in the following, we would determine the assigment varible and flag variable of f // and we denote the assigment variable and flag variable of f by f_av and f_fv respectively for short. //The target expression 'Tar' is determined according to the assigment variable and flag variable of each condition f //In particular, Tar= sum(f in Conset) f_av +(-10000)*f_fv, where Conset is the set of conditions. //If the size of f is 1(excluding the constant), namely f consists of only one variable, then we do not need extra operations. if (Varlist.Count == 1) { //if consflag[i]=1, then it means that there is a constant 1 in f. //In this case, we add (-1.0*f_av) to Tar and increase con by 1 which is added to Tar in the end. if (consflag[i] == 1) { Tar.AddTerm(-1.0, Varlist[0]); con++; } else { Tar.AddTerm(1.0, Varlist[0]); } //add -10000*f_fv to Tar Tar.AddTerm(-10000, VarFlaglist[0]); rec_loc1[i] = loc1; rec_locf[i] = locf; } //If f is the XOR of two variables(assumin that f=u1+u2+c), where c is a constant in {0,1}. //then we shoule calclate f_av and f_fv according to (u1_av, u2_av) and (u1_fv, u2_fv). if (Varlist.Count == 2) { VarlistCopy.Clear(); GRBVar[] VarFlaglistCopy = new GRBVar[3]; GRBVar[] Vartemplist = new GRBVar[4]; //copy Varlist/VarFlaglist to VarlistCopy/VarFlaglistCopy for (j = 0; j < Varlist.Count(); j++) { VarlistCopy.Add(Varlist[j]); VarFlaglistCopy[j] = VarFlaglist[j]; } VarlistCopy.Add(Uvar[loc1]); //model u1_av+u2_av. Here, VarlistCopy[0]and VarlistCoyp[1] are u1_av and u2_av respectively. AddCons2Vars(model, VarlistCopy); //model u1_av+u2_av+c. if consflag[i]=1, then c is 1. In this case, we add an constant variable Consvar[loc0] to the model //and model u1_av+u2_av+c. if (consflag[i] == 1) { model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString()); VarlistCopy[0] = Uvar[loc1]; VarlistCopy[1] = Consvar[loc0 - 1]; VarlistCopy[2] = Uvar[loc1 + 1]; //Console.WriteLine("*****\n" + loc1 + "\n******\n" + loc0 + "\n*****\n"); loc1++; AddCons2Vars(model, VarlistCopy); } //until now, Uvar[loc1] is corresponding to beta_d in Proposition 2 of our paper. //Then, we shall show how to obtain the final assignment/flag variable of f. //UF flip the variables model.AddConstr(NUvar[loc3++] == 1 - VarFlaglist[0], "Flip1" + (loc3).ToString()); model.AddConstr(NUvar[loc3++] == 1 - VarFlaglist[1], "Flip2" + (loc3).ToString()); VarFlaglistCopy[0] = NUvar[loc3 - 1]; VarFlaglistCopy[1] = VarFlaglist[0]; //Vvar[loc2++]=min(1 - VarFlaglist[1], VarFlaglist[0]). Vvar[loc2] corresponds to T_j in Proposition 2. model.AddGenConstrMin(Vvar[loc2++], VarFlaglistCopy, 1000, "FlagTransOxr1" + loc2.ToString()); VarFlaglistCopy[0] = NUvar[loc3 - 2]; VarFlaglistCopy[1] = VarFlaglist[1]; //Vvar[loc2++]=min(1 - VarFlaglist[0], VarFlaglist[1]). Vvar[loc2] corresponds to T_j in Proposition 2. model.AddGenConstrMin(Vvar[loc2++], VarFlaglistCopy, 1000, "FlagTransOxr2" + loc2.ToString()); //UFvar[loc1]=Vvar[loc2-1]+Vvar[loc2-2], UFvar[loc1] is the flag variable of f // model.AddConstr(UFvar[loc1] == Vvar[loc2 - 1] + Vvar[loc2 - 2], "FlagTransOxr3" + loc2.ToString()); for (j = 0; j < Varlist.Count; j++) { Vartemplist[j] = Vvar[loc2 - 1 - j]; } //UFvar[locf]=max(Vvar[loc2],Vvar[loc2-1],...,). is equivalent to UFvar[locf]= Vvar[loc2]+Vvar[loc2-1]+...+ //since only one of Vvar[loc2],Vvar[loc2-1],..., is equal to 1. //UFvar[locf] is the flag variable of f, corresponding to F_d in Proposition 2. model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString()); //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1. NUFvar[loc4] corresponds to 1-F_d in Proposition 2. model.AddConstr(NUFvar[loc4++] == 1 - UFvar[locf], "Flip3" + loc4.ToString()); //max(u1_fv,u2_fv). bvar[locb] corresponds to b_d in Proposition 2. VarFlaglistCopy[0] = VarFlaglist[0]; VarFlaglistCopy[1] = VarFlaglist[1]; model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString()); //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1. NUFvar[loc4] corresponds to 1-b_d in Proposition 2. model.AddConstr(NUFvar[loc4++] == 1 - bvar[locb - 1], "Flip3" + loc4.ToString()); VarFlaglistCopy[0] = NUFvar[loc4 - 1]; //corresponding to 1-F_d VarFlaglistCopy[1] = NUFvar[loc4 - 2]; //corresponding to 1-b_d VarFlaglistCopy[2] = Uvar[loc1]; //corresponding to beta_d loc1++; //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the assigment variable of f. model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy, 1000, "minav" + loc1.ToString()); //model.Update(); Tar.AddTerm(1.0, Uvar[loc1]); Tar.AddTerm(-10000, UFvar[locf]); rec_loc1[i] = loc1; rec_locf[i] = locf; loc1++; locf++; } //in this case, assume that f=u1+u2+u3+c if (Varlist.Count == 3) { VarlistCopy.Clear(); GRBVar[] VarFlaglistCopy = new GRBVar[4]; GRBVar[] VarFlaglistCopy2 = new GRBVar[4]; GRBVar[] Vartemplist = new GRBVar[4]; for (j = 0; j < Varlist.Count(); j++) { VarlistCopy.Add(Varlist[j]); VarFlaglistCopy[j] = VarFlaglist[j]; } VarlistCopy.Add(Uvar[loc1]); //Uvar[loc1]=u1+u2+u3 AddCons3Vars(model, VarlistCopy); //model.AddGenConstrMax(UFvar[loc1], VarFlaglistCopy, 0, "TransFlagXor" + loc1.ToString()); //if c==1, namely f has the constant term 1, U[loc1+1]=Uvar[loc]+1 if (consflag[i] == 1) { model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString()); VarlistCopy[0] = Uvar[loc1]; VarlistCopy[1] = Consvar[loc0 - 1]; VarlistCopy[2] = Uvar[loc1 + 1]; loc1++; AddCons2Vars(model, VarlistCopy); } //filp every variable, for (j = 0; j < Varlist.Count; j++) { model.AddConstr(NUvar[loc3++] == 1 - VarFlaglistCopy[j], "Flip" + j.ToString()); } // for (j = 0; j < Varlist.Count; j++) { for (k = 0; k < Varlist.Count; k++) { if (k != j) { Vartemplist[k] = NUvar[loc3 - 1 - (Varlist.Count - 1 - k)]; } else { Vartemplist[k] = VarFlaglistCopy[k]; } } //Vvar[loc2]=min(1-VarFlaglistCopy[0],1-VarFlaglistCopy[2],...,VarFlaglistCopy[j],1-VarFlaglistCopy[j],...) model.AddGenConstrMin(Vvar[loc2++], Vartemplist, 1000, "FlagTransOxr1" + loc2.ToString()); } for (j = 0; j < Varlist.Count; j++) { Vartemplist[j] = Vvar[loc2 - 1 - j]; } //Since only one of Vvar[loc2 - 1],Vvar[loc2 - 2],..., is equal to 0 and the remainings are equal to 0s, //UFvar[loc1]=max(Vvar[loc2 - 1],Vvar[loc2 - 2],...,) is equivalently to UFvar[loc1]=Vvar[loc2 - 1]+Vvar[loc2 - 2]+...+ //UFvar[loc1]is the fianl flag variable of f model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString()); //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1 model.AddConstr(NUFvar[loc4++] == 1 - UFvar[locf], "Flip3" + loc4.ToString()); //max(u1_fv,u2_fv,u3_fv) VarFlaglistCopy[0] = VarFlaglist[0]; VarFlaglistCopy[1] = VarFlaglist[1]; VarFlaglistCopy[2] = VarFlaglist[2]; model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString()); //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1 model.AddConstr(NUFvar[loc4++] == 1 - bvar[locb - 1], "Flip3" + loc4.ToString()); VarFlaglistCopy2[0] = NUFvar[loc4 - 1]; VarFlaglistCopy2[1] = NUFvar[loc4 - 2]; VarFlaglistCopy2[2] = Uvar[loc1]; loc1++; //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the assigment variable of f. model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy2, 1000, "min_av" + loc1.ToString()); Tar.AddTerm(1.0, Uvar[loc1]); Tar.AddTerm(-10000, UFvar[locf]); rec_loc1[i] = loc1; rec_locf[i] = locf; loc1++; locf++; } //assuming f=u1+u2+u3+u4+c if (Varlist.Count == 4) { List <GRBVar> templist = new List <GRBVar>() { }; GRBVar[] VarFlaglistCopy = new GRBVar[5]; GRBVar[] VarFlaglistCopy2 = new GRBVar[5]; GRBVar[] Vartemplist = new GRBVar[5]; for (j = 0; j < Varlist.Count(); j++) { VarFlaglistCopy[j] = VarFlaglist[j]; } templist.Add(Varlist[0]); templist.Add(Varlist[1]); templist.Add(Uvar[loc1]); AddCons2Vars(model, templist); templist.Clear(); loc1++; templist.Add(Varlist[2]); templist.Add(Varlist[3]); templist.Add(Uvar[loc1]); AddCons2Vars(model, templist); templist.Clear(); loc1++; templist.Add(Uvar[loc1 - 2]); templist.Add(Uvar[loc1 - 1]); templist.Add(Uvar[loc1]); AddCons2Vars(model, templist); //if c==1 if (consflag[i] == 1) { model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString()); VarlistCopy[0] = Uvar[loc1]; VarlistCopy[1] = Consvar[loc0 - 1]; VarlistCopy[2] = Uvar[loc1 + 1]; loc1++; AddCons2Vars(model, VarlistCopy); } for (j = 0; j < Varlist.Count; j++) { model.AddConstr(NUvar[loc3++] == 1 - VarFlaglistCopy[j], "Flip" + j.ToString()); } for (j = 0; j < Varlist.Count; j++) { for (k = 0; k < Varlist.Count; k++) { if (k != j) { Vartemplist[k] = NUvar[loc3 - 1 - (Varlist.Count - 1 - k)]; } else { Vartemplist[k] = VarFlaglistCopy[k]; } } model.AddGenConstrMin(Vvar[loc2++], Vartemplist, 1000, "FlagTransOxr1" + loc2.ToString()); } for (j = 0; j < Varlist.Count; j++) { Vartemplist[j] = Vvar[loc2 - 1 - j]; } model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString()); //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1 model.AddConstr(NUFvar[loc4] == 1 - UFvar[locf], "Flip3" + loc4.ToString()); loc4++; //max(u1_fv,u2_fv,u3_fv,u4_fv) VarFlaglistCopy[0] = VarFlaglist[0]; VarFlaglistCopy[1] = VarFlaglist[1]; VarFlaglistCopy[2] = VarFlaglist[2]; VarFlaglistCopy[3] = VarFlaglist[3]; model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString()); //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1 model.AddConstr(NUFvar[loc4] == 1 - bvar[locb - 1], "Flip4" + loc4.ToString()); loc4++; //VarFlaglistCopy.Initialize(); VarFlaglistCopy2[0] = NUFvar[loc4 - 1]; VarFlaglistCopy2[1] = NUFvar[loc4 - 2]; VarFlaglistCopy2[2] = Uvar[loc1]; loc1++; //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the assigment variable of f. model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy2, 1000, "min_av" + loc1.ToString()); //Tar=Tar+assigment variable +(-10000)*flag variable Tar.AddTerm(1.0, Uvar[loc1]); Tar.AddTerm(-10000, UFvar[locf]); rec_loc1[i] = loc1; rec_locf[i] = locf; loc1++; locf++; } //assuming f=u1+u2+u3+u4+u5+c if (Varlist.Count == 5) { List <GRBVar> templist = new List <GRBVar>() { }; GRBVar[] VarFlaglistCopy = new GRBVar[6]; GRBVar[] VarFlaglistCopy2 = new GRBVar[6]; GRBVar[] Vartemplist = new GRBVar[6]; for (j = 0; j < Varlist.Count(); j++) { VarFlaglistCopy[j] = VarFlaglist[j]; } templist.Add(Varlist[0]); templist.Add(Varlist[1]); templist.Add(Uvar[loc1]); AddCons2Vars(model, templist); templist.Clear(); loc1++; templist.Add(Varlist[2]); templist.Add(Varlist[3]); templist.Add(Varlist[4]); templist.Add(Uvar[loc1]); AddCons3Vars(model, templist); templist.Clear(); loc1++; templist.Add(Uvar[loc1 - 2]); templist.Add(Uvar[loc1 - 1]); templist.Add(Uvar[loc1]); AddCons2Vars(model, templist); if (consflag[i] == 1) { model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString()); VarlistCopy[0] = Uvar[loc1]; VarlistCopy[1] = Consvar[loc0 - 1]; VarlistCopy[2] = Uvar[loc1 + 1]; loc1++; AddCons2Vars(model, VarlistCopy); } for (j = 0; j < Varlist.Count; j++) { model.AddConstr(NUvar[loc3++] == 1 - VarFlaglistCopy[j], "Flip" + j.ToString()); } //flip and calculate Tj for (j = 0; j < Varlist.Count; j++) { for (k = 0; k < Varlist.Count; k++) { if (k != j) { Vartemplist[k] = NUvar[loc3 - 1 - (Varlist.Count - 1 - k)]; } else { Vartemplist[k] = VarFlaglistCopy[k]; } } model.AddGenConstrMin(Vvar[loc2++], Vartemplist, 1000, "FlagTransOxr1" + loc2.ToString()); } // for (j = 0; j < Varlist.Count; j++) { Vartemplist[j] = Vvar[loc2 - 1 - j]; } model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString()); //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1 model.AddConstr(NUFvar[loc4++] == 1 - UFvar[locf], "Flip3" + loc4.ToString()); //max(u1_fv,u2_fv,u3_fv,u4_fv,u5_fv) VarFlaglistCopy[0] = VarFlaglist[0]; VarFlaglistCopy[1] = VarFlaglist[1]; VarFlaglistCopy[2] = VarFlaglist[2]; VarFlaglistCopy[3] = VarFlaglist[3]; VarFlaglistCopy[4] = VarFlaglist[4]; model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString()); //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1 model.AddConstr(NUFvar[loc4++] == 1 - bvar[locb - 1], "Flip4" + loc4.ToString()); VarFlaglistCopy2[0] = NUFvar[loc4 - 1]; VarFlaglistCopy2[1] = NUFvar[loc4 - 2]; VarFlaglistCopy2[2] = Uvar[loc1]; loc1++; //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the assigment variable of f. model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy2, 1000, "min_av" + loc1.ToString()); Tar.AddTerm(1.0, Uvar[loc1]); Tar.AddTerm(-10000, UFvar[locf]); rec_loc1[i] = loc1; rec_locf[i] = locf; loc1++; locf++; } //Console.WriteLine("5: " +loc1); //assuming that f=u1+u2+u3+u4+u5...+um+c, where m>5. if (Varlist.Count > 5) { int length; length = Varlist.Count; List <GRBVar> curvarlist = new List <GRBVar>() { }; GRBVar[] VarFlaglistCopy = new GRBVar[Varlist.Count + 1]; GRBVar[] VarFlaglistCopy2 = new GRBVar[Varlist.Count + 1]; GRBVar[] Vartemplist = new GRBVar[Varlist.Count + 1]; for (j = 0; j < Varlist.Count; j++) { curvarlist.Add(Varlist[j]); VarFlaglistCopy[j] = VarFlaglist[j]; } //model f=u1+u2+...+un. The method used here is a slight differnt from that presented in the paper. //The method used here is more convenient for coding. while (length > 3) { List <GRBVar> nextvarlist = new List <GRBVar>() { }; List <GRBVar> templist = new List <GRBVar>() { }; // templist.Add(curvarlist[0]); templist.Add(curvarlist[1]); templist.Add(curvarlist[2]); templist.Add(Uvar[loc1]); AddCons3Vars(model, templist); for (j = 3; j < curvarlist.Count; j++) { nextvarlist.Add(curvarlist[j]); } nextvarlist.Add(Uvar[loc1]); curvarlist.Clear(); for (j = 0; j < nextvarlist.Count; j++) { curvarlist.Add(nextvarlist[j]); } length = curvarlist.Count; loc1++; } if (length == 2) { curvarlist.Add(Uvar[loc1]); AddCons2Vars(model, curvarlist); //if c==1, then we need xor one more constant if (consflag[i] == 1) { model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString()); VarlistCopy[0] = Uvar[loc1]; VarlistCopy[1] = Consvar[loc0 - 1]; VarlistCopy[2] = Uvar[loc1 + 1]; loc1++; AddCons2Vars(model, VarlistCopy); } } if (length == 3) { curvarlist.Add(Uvar[loc1]); AddCons3Vars(model, curvarlist); //if c==1, then we need xor one more constant if (consflag[i] == 1) { model.AddConstr(Consvar[loc0++] == 1, "Flip" + j.ToString()); VarlistCopy[0] = Uvar[loc1]; VarlistCopy[1] = Consvar[loc0 - 1]; VarlistCopy[2] = Uvar[loc1 + 1]; loc1++; AddCons2Vars(model, VarlistCopy); } } for (j = 0; j < Varlist.Count; j++) { model.AddConstr(NUvar[loc3++] == 1 - VarFlaglistCopy[j], "Flip" + j.ToString()); } for (j = 0; j < Varlist.Count; j++) { for (k = 0; k < Varlist.Count; k++) { if (k != j) { Vartemplist[k] = NUvar[loc3 - 1 - (Varlist.Count - 1 - k)]; } else { Vartemplist[k] = VarFlaglistCopy[k]; } } model.AddGenConstrMin(Vvar[loc2++], Vartemplist, 1000, "FlagTransOxr1" + loc2.ToString()); } for (j = 0; j < Varlist.Count; j++) { Vartemplist[j] = Vvar[loc2 - 1 - j]; } model.AddGenConstrMax(UFvar[locf], Vartemplist, 0, "FlagTransXor-2" + loc2.ToString()); //NUFvar[loc4] =1-UFvar[loc1] and increase loc4 by 1 model.AddConstr(NUFvar[loc4++] == 1 - UFvar[locf], "Flip3" + loc4.ToString()); //bvar[locb]=max(u1_fv,u2_fv,u3_fv,u4_fv,...,un_fv) and increase locb by 1 for (j = 0; j < VarFlaglist.Count; j++) { VarFlaglistCopy[j] = VarFlaglist[j]; } model.AddGenConstrMax(bvar[locb++], VarFlaglistCopy, 0, "maxfv" + locb.ToString()); //NUFvar[loc4] =1-bvar[locb++] and increase loc4 by 1 model.AddConstr(NUFvar[loc4++] == 1 - bvar[locb - 1], "Flip4" + loc4.ToString()); VarFlaglistCopy2[0] = NUFvar[loc4 - 1]; VarFlaglistCopy2[1] = NUFvar[loc4 - 2]; VarFlaglistCopy2[2] = Uvar[loc1]; loc1++; //Uvar[loc1]=min(NUFvar[loc4-1],NUFvar[loc4-2],loc1), is the assigment variable of f. model.AddGenConstrMin(Uvar[loc1], VarFlaglistCopy2, 1000, "min_av" + loc1.ToString()); Tar.AddTerm(1.0, Uvar[loc1]); Tar.AddTerm(-10000, UFvar[locf]); rec_loc1[i] = loc1; rec_locf[i] = locf; loc1++; locf++; } } // GRBLinExpr keyspace = new GRBLinExpr(); for (i = 0; i < 80; i++) { keyspace.AddTerm(1.0, kvf[i]); } Tar.AddConstant((double)con); //Add the condition that Tar>=0. It gurantees that there is not any condition whose flag variable is equal to 1. model.AddConstr(Tar == 3, "finalcons"); model.SetObjective(keyspace, GRB.MAXIMIZE); //Set the objective function of the model. //model.SetObjective(Tar, GRB.MINIMIZE); model.Optimize(); //output the states of key variables and iv variables if (model.SolCount > 0) { sw.WriteLine("****************************Conditions on single key/iv variables***************************\n"); Console.Write("Free Key bits:\n"); sw.Write("Free Key bits:\n"); for (i = 0; i < 80; i++) { if ((keyvar[i].X == 0) && (kvf[i].X == 1)) { Console.Write(i + ","); sw.Write(i + ","); } } Console.WriteLine(); sw.WriteLine(); Console.Write("Key bits set to 1:\n"); sw.Write("Key bits set to 1:\n"); for (i = 0; i < 80; i++) { if ((keyvar[i].X == 1) && (kvf[i].X == 0)) { Console.Write(i + ","); sw.Write(i + ","); } } Console.WriteLine(); sw.WriteLine(); Console.Write("Key bits set 0:\n"); sw.Write("Key bits set 0:\n"); for (i = 0; i < 80; i++) { if ((keyvar[i].X == 0) && (kvf[i].X == 0)) { Console.Write(i + ","); sw.Write(i + ","); } } Console.WriteLine(); sw.WriteLine(); //for (i = 0; i < loc2; i++) //{ // if (Vvar[i].X > 1) // { // Console.Write(Vvar[i].VarName + " " + Vvar[i].X + "\n"); // } //} Console.WriteLine("*******************************************************\n"); sw.WriteLine("*******************************************************\n"); Console.Write("Free Iv bits:\n"); sw.Write("Free Iv bits:\n"); for (i = 0; i < 80; i++) { if ((ivvar[i].X == 0) && (vvf[i].X == 1)) { Console.Write(i + ","); sw.Write(i + ","); } } Console.WriteLine(); sw.WriteLine(); Console.Write("Iv bits set to 1:\n"); sw.Write("Iv bits set to 1:\n"); for (i = 0; i < 80; i++) { if ((ivvar[i].X == 1) && (vvf[i].X == 0)) { Console.Write(i + ","); sw.Write(i + ","); } } Console.WriteLine(); sw.WriteLine(); Console.Write("Iv bits set to 0:\n"); sw.Write("Iv bits set to 0:\n"); for (i = 0; i < 80; i++) { if ((ivvar[i].X == 0) && (vvf[i].X == 0)) { Console.Write(i + ","); sw.Write(i + ","); } } Console.WriteLine(); sw.WriteLine(); double aa = Tar.Value; Console.WriteLine("*****************The number of 1's*****************"); Console.WriteLine(aa); Console.WriteLine("***************************************************"); sw.WriteLine("***********************The assigment/flag variable of key and iv variables***********************"); for (i = 0; i < 80; i++) { Console.Write(keyvar[i].VarName + "= " + keyvar[i].X + " " + kvf[i].VarName + "= " + kvf[i].X + "\n"); sw.Write(keyvar[i].VarName + "= " + keyvar[i].X + " " + kvf[i].VarName + "= " + kvf[i].X + "\n"); } Console.WriteLine("*******************************"); for (i = 0; i < 80; i++) { Console.Write(ivvar[i].VarName + "= " + ivvar[i].X + " " + vvf[i].VarName + "= " + vvf[i].X + "\n"); sw.Write(ivvar[i].VarName + "= " + ivvar[i].X + " " + vvf[i].VarName + "= " + vvf[i].X + "\n"); } Console.WriteLine(); // StreamReader rw = new StreamReader("ConSet.txt"); sw.WriteLine("***************The concrete conditions****************"); for (j = 0; j < consnum; j++) { string onecon = rw.ReadLine(); sw.WriteLine(onecon + "=" + Uvar[rec_loc1[j]].X); } sw.Close(); } }
private static bool GurobiSolve(GRBEnv env, int rows, int cols, double[] c, // linear portion of objective function double[,] Q, // quadratic portion of objective function double[,] A, // constraint matrix double[] rhs, // RHS vector double[] lb, // variable lower bounds double[] ub, // variable upper bounds char[] vtype, // variable types (continuous, binary, etc.) double[] solution, ref double val) { bool success = false; try { GRBModel model = new GRBModel(env); // Add variables to the model GRBVar[] vars = model.AddVars(lb, ub, null, null, null); model.Update(); // Populate A matrix for (int i = 0; i < rows; i++) { GRBLinExpr expr = new GRBLinExpr(); for (int j = 0; j < cols; j++) { if (A[i, j] != 0) { expr.AddTerm(A[i, j], vars[j]); // Note: '+=' would be much slower } } model.AddConstr(expr, '>', rhs[i], ""); } // Populate objective GRBQuadExpr obj = new GRBQuadExpr(); if (Q != null) { for (int i = 0; i < cols; i++) { for (int j = 0; j < cols; j++) { if (Q[i, j] != 0) { obj.AddTerm(Q[i, j], vars[i], vars[j]); // Note: '+=' would be much slower } } } for (int j = 0; j < cols; j++) { if (c[j] != 0) { obj.AddTerm(c[j], vars[j]); // Note: '+=' would be much slower } } model.SetObjective(obj, GRB.MAXIMIZE); } // Solve model model.Optimize(); // Extract solution if (model.Get(GRB.IntAttr.Status) == GRB.Status.OPTIMAL) { success = true; for (int j = 0; j < cols; j++) { solution[j] = vars[j].Get(GRB.DoubleAttr.X); } } else { success = false; } val = obj.Value; model.Dispose(); } catch (GRBException e) { return(false); } return(success); }