static void Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("Usage: feasopt_cs filename"); return; } try { GRBEnv env = new GRBEnv(); GRBModel feasmodel = new GRBModel(env, args[0]); // Create a copy to use FeasRelax feature later */ GRBModel feasmodel1 = new GRBModel(feasmodel); // Clear objective feasmodel.SetObjective(new GRBLinExpr()); // Add slack variables GRBConstr[] c = feasmodel.GetConstrs(); for (int i = 0; i < c.Length; ++i) { char sense = c[i].Get(GRB.CharAttr.Sense); if (sense != '>') { GRBConstr[] constrs = new GRBConstr[] { c[i] }; double[] coeffs = new double[] { -1 }; feasmodel.AddVar(0.0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, constrs, coeffs, "ArtN_" + c[i].Get(GRB.StringAttr.ConstrName)); } if (sense != '<') { GRBConstr[] constrs = new GRBConstr[] { c[i] }; double[] coeffs = new double[] { 1 }; feasmodel.AddVar(0.0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, constrs, coeffs, "ArtP_" + c[i].Get(GRB.StringAttr.ConstrName)); } } feasmodel.Update(); // Optimize modified model feasmodel.Write("feasopt.lp"); feasmodel.Optimize(); // Use FeasRelax feature */ feasmodel1.FeasRelax(GRB.FEASRELAX_LINEAR, true, false, true); feasmodel1.Write("feasopt1.lp"); feasmodel1.Optimize(); // Dispose of model and env feasmodel1.Dispose(); feasmodel.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { GRBEnv env = new GRBEnv("mip1.log"); GRBModel model = new GRBModel(env); // Create variables GRBVar x = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "x"); GRBVar y = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "y"); GRBVar z = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "z"); // Integrate new variables model.Update(); // Set objective: maximize x + y + 2 z model.SetObjective(x + y + 2 * z, GRB.MAXIMIZE); // Add constraint: x + 2 y + 3 z <= 4 model.AddConstr(x + 2 * y + 3 * z <= 4.0, "c0"); // Add constraint: x + y >= 1 model.AddConstr(x + y >= 1.0, "c1"); // Optimize model model.Optimize(); Console.WriteLine(x.Get(GRB.StringAttr.VarName) + " " + x.Get(GRB.DoubleAttr.X)); Console.WriteLine(y.Get(GRB.StringAttr.VarName) + " " + y.Get(GRB.DoubleAttr.X)); Console.WriteLine(z.Get(GRB.StringAttr.VarName) + " " + z.Get(GRB.DoubleAttr.X)); Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal)); // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public HttpResponseMessage Optimize(string RunName) { using (var dbConn = new ApplicationDbContext()) { //Variables for students, semesters, courses, and course/semester offerings students = dbConn.StudentPreferences.Where(m => m.IsActive == true).Include(m => m.Courses).Include(m => m.Student.CompletedCourses).OrderByDescending(m => m.Student.CompletedCourses.Count()).ToArray(); crssems = dbConn.CourseSemesters.Where(m => m.IsActive == true).Include(m => m.Course).Include(m => m.Semester).ToArray(); courses = crssems.Select(m => m.Course).Distinct().ToArray(); sems = crssems.Select(m => m.Semester).Distinct().OrderBy(m => m.Type).OrderBy(m => m.Year).ToArray(); var completed = dbConn.CompletedCourses.ToList(); try { GRBEnv env = new GRBEnv("mip1.log"); GRBModel model = new GRBModel(env); model.Set(GRB.StringAttr.ModelName, "Course Optimizer"); GRBVar[,] slacks = new GRBVar[courses.Length, sems.Length]; //Assignment of student, course, and semester. Student must have a desire to take the coure, has not taken the course, and the course is offered to be included GRBVar[,,] CourseAllocation = new GRBVar[students.Length, courses.Length, sems.Length]; for (int i = 0; i < students.Length; i++) { for (int j = 0; j < courses.Length; j++) { for (int k = 0; k < sems.Length; k++) { if (students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID) && crssems.Contains(crssems.SingleOrDefault(m => m.Course == courses[j] && m.Semester == sems[k]))) CourseAllocation[i, j, k] = model.AddVar(0, 1, 1, GRB.BINARY, "students." + (i + 1).ToString() + "_Course." + (j + 1).ToString() + "_Semester." + (k + 1).ToString()); else CourseAllocation[i, j, k] = model.AddVar(0, 0, 1, GRB.BINARY, "students." + (i + 1).ToString() + "_Course." + (j + 1).ToString() + "_Semester." + (k + 1).ToString()); } } } model.Set(GRB.IntAttr.ModelSense, 1); model.Update(); //MUST TAKE DESIRED COURSE ONLY ONCE //Constrains the students to only take courses they desire once and for when the course is offered and does not allow a repeat of a course in another semester for (int i = 0; i < students.Length; i++) { for (int j = 0; j < courses.Length; j++) { if (students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID)) { GRBLinExpr constStudentDesiredCourses = 0.0; for (int k = 0; k < sems.Length; k++) { if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year)) constStudentDesiredCourses.AddTerm(1.0, CourseAllocation[i, j, k]); } String sStudentDesiredCourses = "DesiredCourse." + j + 1 + "_Student." + i + 1; model.AddConstr(constStudentDesiredCourses == 1, sStudentDesiredCourses); } } //MAX COURSES PER SEMESTER //Constrains the students to only have a maximum number of 2 courses per semester. for (int k = 0; k < sems.Length; k++) { GRBLinExpr constMaxPerSem = 0.0; for (int j = 0; j < courses.Length; j++) { if (!completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID) && (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year))) constMaxPerSem.AddTerm(1, CourseAllocation[i, j, k]); } String sCourseSem = "maxCourseStudent." + i + 1 + "_Semester." + k + 1; model.AddConstr(constMaxPerSem <= MAX_COURSES_PER_SEMESTER, sCourseSem); } //PREREQUISITES //Constrains the students to take prerequisite courses prior to taking a course that needs the prerequisite for (int j = 0; j < courses.Length; j++) { if (courses[j].Prerequisites.Any() && students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID)) { foreach (var prereq in courses[j].Prerequisites) { int prereqIndex = Array.IndexOf(courses, prereq); GRBLinExpr coursePrereqConst1 = 0.0; GRBLinExpr coursePrereqConst2 = 0.0; if (!completed.Any(m => m.GaTechId == students[i].GaTechId && m.Course.ID == prereq.ID)) { for (int k = 0; k < sems.Length; k++) { if (prereqIndex >= 0) { coursePrereqConst1.AddTerm(k + 1, CourseAllocation[i, prereqIndex, k]); coursePrereqConst2.AddTerm(k, CourseAllocation[i, j, k]); } } } model.AddConstr(coursePrereqConst1, GRB.LESS_EQUAL, coursePrereqConst2, "PREREQ_Student" + i + "_Course+" + j + "_Prereq" + prereqIndex); } } } } //SENIORITY //Students are already ordered from dB query by seniority in descending order and puts a preference to senior students over the next student that desires that //same course with less seniority. for (int j = 0; j < courses.Length; j++) { for (int i = 0; i < students.Length - 1; i++) { if (students[i].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID)) { int SemsRemain = (students[i].Courses.Count - students[i].Student.CompletedCourses.Count) / 2 + (students[i].Courses.Count - students[i].Student.CompletedCourses.Count) % 2; for (int n = i + 1; n < students.Length; n++) { if (students[n].Courses.Contains(courses[j]) && !completed.Any(m => m.GaTechId == students[n].GaTechId && courses[j].ID == m.Course_ID)) { GRBLinExpr seniority = 0.0; for (int k = 0; k < sems.Length; k++) { if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year)) { if (k <= SemsRemain) { seniority.AddTerm(1.0, CourseAllocation[i, j, k]); seniority.AddTerm(-1.0, CourseAllocation[n, j, k]); } else { seniority.AddTerm(-1.0, CourseAllocation[i, j, k]); seniority.AddTerm(1.0, CourseAllocation[n, j, k]); } } } model.AddConstr(seniority, GRB.GREATER_EQUAL, 0, "Seniority for Student." + students[i] + "_Course." + courses[j]); break; } } } } } //Add the slack variable for all semester & course offerings then constrain the maximum number of students //to take a couse in a semester. for (int k = 0; k < sems.Length; k++) { for (int j = 0; j < courses.Length; j++) { if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year)) { slacks[j, k] = model.AddVar(0, GRB.INFINITY, 0, GRB.INTEGER, sems[k].Type.ToString() + "." + sems[k].Year.ToString() + "." + courses[j].Name + ".Slacks"); GRBLinExpr constMaxStudCrsSem = 0.0; for (int i = 0; i < students.Length; i++) { if (!completed.Any(m => m.GaTechId == students[i].GaTechId && courses[j].ID == m.Course_ID)) constMaxStudCrsSem.AddTerm(1.0, CourseAllocation[i, j, k]); } model.Update(); constMaxStudCrsSem.AddTerm(-1.0, slacks[j, k]); model.AddConstr(constMaxStudCrsSem <= crssems.Single(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year).StudentLimit, sems[k].Type.ToString() + "." + sems[k].Year.ToString() + "." + courses[j].Name); } } } //Add total slack to the optimization model for all courses in the semesters they are offered. GRBVar totSlack = model.AddVar(0, GRB.INFINITY, 0, GRB.INTEGER, "totSlack"); GRBLinExpr lhs = new GRBLinExpr(); lhs.AddTerm(-1.0, totSlack); for (int j = 0; j < courses.Length; j++) { for (int k = 0; k < sems.Length; k++) { if (crssems.Any(m => m.Course.ID == courses[j].ID && m.Semester.Type == sems[k].Type && m.Semester.Year == sems[k].Year)) lhs.AddTerm(1.0, slacks[j, k]); } } model.Update(); model.AddConstr(lhs, GRB.EQUAL, 0, "totSlack"); // Objective: minimize the total slack GRBLinExpr obj = new GRBLinExpr(); obj.AddTerm(1.0, totSlack); model.SetObjective(obj); //Optimize the model to minimize the total slack and maximize students to course offerings based on input variables and constraints. model.Optimize(); //Write Results optimization results to database writeResults(CourseAllocation, students, courses, sems, crssems, dbConn, Convert.ToInt32(model.Get(GRB.DoubleAttr.ObjVal)), RunName); //Clean-Up model.Dispose(); env.Dispose(); } catch (Exception e) { return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "An Error occured while running the optimization."); } } return Request.CreateResponse(HttpStatusCode.OK); }
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; }
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); }
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); }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[, ] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.ModelName = "assignment"; // Assignment variables: x[w][s] == 1 if worker w is assigned // to shift s. This is no longer a pure assignment model, so we must // use binary variables. GRBVar[,] x = new GRBVar[nWorkers, nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w, s] = model.AddVar(0, availability[w, s], 0, GRB.BINARY, Workers[w] + "." + Shifts[s]); } } // Slack variables for each shift constraint so that the shifts can // be satisfied GRBVar[] slacks = new GRBVar[nShifts]; for (int s = 0; s < nShifts; ++s) { slacks[s] = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, Shifts[s] + "Slack"); } // Variable to represent the total slack GRBVar totSlack = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "totSlack"); // Variables to count the total shifts worked by each worker GRBVar[] totShifts = new GRBVar[nWorkers]; for (int w = 0; w < nWorkers; ++w) { totShifts[w] = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, Workers[w] + "TotShifts"); } GRBLinExpr lhs; // Constraint: assign exactly shiftRequirements[s] workers // to each shift s, plus the slack for (int s = 0; s < nShifts; ++s) { lhs = new GRBLinExpr(); lhs.AddTerm(1.0, slacks[s]); for (int w = 0; w < nWorkers; ++w) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs == shiftRequirements[s], Shifts[s]); } // Constraint: set totSlack equal to the total slack lhs = new GRBLinExpr(); for (int s = 0; s < nShifts; ++s) { lhs.AddTerm(1.0, slacks[s]); } model.AddConstr(lhs == totSlack, "totSlack"); // Constraint: compute the total number of shifts for each worker for (int w = 0; w < nWorkers; ++w) { lhs = new GRBLinExpr(); for (int s = 0; s < nShifts; ++s) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs == totShifts[w], "totShifts" + Workers[w]); } // Objective: minimize the total slack model.SetObjective(1.0 * totSlack); // Optimize int status = solveAndPrint(model, totSlack, nWorkers, Workers, totShifts); if (status != GRB.Status.OPTIMAL) { return; } // Constrain the slack by setting its upper and lower bounds totSlack.UB = totSlack.X; totSlack.LB = totSlack.X; // Variable to count the average number of shifts worked GRBVar avgShifts = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "avgShifts"); // Variables to count the difference from average for each worker; // note that these variables can take negative values. GRBVar[] diffShifts = new GRBVar[nWorkers]; for (int w = 0; w < nWorkers; ++w) { diffShifts[w] = model.AddVar(-GRB.INFINITY, GRB.INFINITY, 0, GRB.CONTINUOUS, Workers[w] + "Diff"); } // Constraint: compute the average number of shifts worked lhs = new GRBLinExpr(); for (int w = 0; w < nWorkers; ++w) { lhs.AddTerm(1.0, totShifts[w]); } model.AddConstr(lhs == nWorkers * avgShifts, "avgShifts"); // Constraint: compute the difference from the average number of shifts for (int w = 0; w < nWorkers; ++w) { model.AddConstr(totShifts[w] - avgShifts == diffShifts[w], Workers[w] + "Diff"); } // Objective: minimize the sum of the square of the difference from the // average number of shifts worked GRBQuadExpr qobj = new GRBQuadExpr(); for (int w = 0; w < nWorkers; ++w) { qobj.AddTerm(1.0, diffShifts[w], diffShifts[w]); } model.SetObjective(qobj); // Optimize status = solveAndPrint(model, totSlack, nWorkers, Workers, totShifts); if (status != GRB.Status.OPTIMAL) { return; } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Amount each worker is paid to work one shift double[] pay = new double[] { 10, 12, 10, 8, 8, 9, 11 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[,] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.Set(GRB.StringAttr.ModelName, "assignment"); // Assignment variables: x[w][s] == 1 if worker w is assigned // to shift s. Since an assignment model always produces integer // solutions, we use continuous variables and solve as an LP. GRBVar[,] x = new GRBVar[nWorkers,nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w,s] = model.AddVar(0, availability[w,s], pay[w], GRB.CONTINUOUS, Workers[w] + "." + Shifts[s]); } } // The objective is to minimize the total pay costs model.Set(GRB.IntAttr.ModelSense, 1); // Update model to integrate new variables model.Update(); // Constraint: assign exactly shiftRequirements[s] workers // to each shift s LinkedList<GRBConstr> reqCts = new LinkedList<GRBConstr>(); for (int s = 0; s < nShifts; ++s) { GRBLinExpr lhs = 0.0; for (int w = 0; w < nWorkers; ++w) lhs += x[w,s]; GRBConstr newCt = model.AddConstr(lhs == shiftRequirements[s], Shifts[s]); reqCts.AddFirst(newCt); } // Optimize model.Optimize(); int status = model.Get(GRB.IntAttr.Status); if (status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is unbounded"); return; } if (status == GRB.Status.OPTIMAL) { Console.WriteLine("The optimal objective is " + model.Get(GRB.DoubleAttr.ObjVal)); return; } if ((status != GRB.Status.INF_OR_UNBD) && (status != GRB.Status.INFEASIBLE)) { Console.WriteLine("Optimization was stopped with status " + status); return; } // Add slack variables to make the model feasible Console.WriteLine("The model is infeasible; adding slack variables"); // Set original objective coefficients to zero model.SetObjective(new GRBLinExpr()); // Add a new slack variable to each shift constraint so that the shifts // can be satisfied LinkedList<GRBVar> slacks = new LinkedList<GRBVar>(); foreach (GRBConstr c in reqCts) { GRBColumn col = new GRBColumn(); col.AddTerm(1.0, c); GRBVar newvar = model.AddVar(0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, col, c.Get(GRB.StringAttr.ConstrName) + "Slack"); slacks.AddFirst(newvar); } // Solve the model with slacks model.Optimize(); status = model.Get(GRB.IntAttr.Status); if ((status == GRB.Status.INF_OR_UNBD) || (status == GRB.Status.INFEASIBLE) || (status == GRB.Status.UNBOUNDED)) { Console.WriteLine("The model with slacks cannot be solved " + "because it is infeasible or unbounded"); return; } if (status != GRB.Status.OPTIMAL) { Console.WriteLine("Optimization was stopped with status " + status); return; } Console.WriteLine("\nSlack values:"); foreach (GRBVar sv in slacks) { if (sv.Get(GRB.DoubleAttr.X) > 1e-6) { Console.WriteLine(sv.Get(GRB.StringAttr.VarName) + " = " + sv.Get(GRB.DoubleAttr.X)); } } // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
public static Graph RunSolver(Graph graph) { GRBEnv env = new GRBEnv(); env.Set(GRB.IntParam.OutputFlag, 0); env.Set(GRB.IntParam.LogToConsole, 0); env.Set(GRB.IntParam.Presolve, 2); env.Set(GRB.DoubleParam.Heuristics, 0.0); GRBModel model = new GRBModel(env); GRBVar[] variables = new GRBVar[graph.NumberOfEdges]; model.SetCallback(new LPSolverCallback()); Dictionary<Edge, GRBVar> edgeVars = new Dictionary<Edge, GRBVar>(); // Add variables to the LP model for (int i = 0; i < graph.NumberOfEdges; i++) { variables[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "x_" + i); edgeVars.Add(graph.Edges[i], variables[i]); } model.Update(); // Add constraints to the LP model Console.Write("\rRunning LP. Creating constraints...\r"); //var nonTerminals = graph.Vertices.Except(graph.Terminals).ToList(); ulong conNr = 0; //var terminalCombinations = new List<List<Vertex>>(); // Assume, without loss of generality, that Terminals[0] is the root, and thus is always included int rootNr = 1; foreach (var rootTerminal in graph.Terminals) //var rootTerminal = graph.Terminals[0]; { Console.Write("\rRunning LP. Creating constraints... {0}/{1}\r", rootNr, graph.Terminals.Count); foreach (var combination in GetBFS(graph, rootTerminal)) { var nodes = combination.ToList(); //new HashSet<Vertex>(combination); if (nodes.Count == graph.NumberOfVertices || graph.Terminals.All(nodes.Contains)) continue; //Debug.WriteLine("Combination: {0}", string.Join(" ", nodes)); //for (int i = 1; i <= nodes.Count; i++) { var edges = nodes//.Take(i) .SelectMany(graph.GetEdgesForVertex) .Distinct() .Where(x => x.WhereOne(y => !nodes.Contains(y))); GRBLinExpr expression = 0; foreach (var edge in edges) expression.AddTerm(1, edgeVars[edge]); model.AddConstr(expression >= 1.0, "subset_" + conNr); conNr++; if (conNr % 100000 == 0) { //model = model.Presolve(); //Pre-solve the model every 1000 constraints. int constrBefore = model.GetConstrs().Length, varsBefore = model.GetVars().Length; Debug.WriteLine("Presolve called."); var presolved = model.Presolve(); Debug.WriteLine("Model has {0} constraints, {1} variables. Presolve has {2} constraints, {3} variables", constrBefore, varsBefore, presolved.GetConstrs().Length, presolved.GetVars().Length); } } } //Debug.WriteLine(" "); //Debug.WriteLine(" "); rootNr++; } //terminalCombinations.Add(new List<Vertex>(new[] { graph.Terminals[0] })); //for (int j = 1; j < graph.Terminals.Count - 1; j++) // terminalCombinations.AddRange(new Combinations<Vertex>(graph.Terminals.Skip(1), j).Select(combination => combination.Union(new[] { graph.Terminals[0] }).ToList())); //long nonTerminalSetsDone = 0; //long nonTerminalSets = 0; //for (int i = 0; i <= nonTerminals.Count; i++) // nonTerminalSets += Combinations<Vertex>.NumberOfCombinations(nonTerminals.Count, i); //for (int i = 0; i <= nonTerminals.Count; i++) //{ // foreach (var nonTerminalSet in new Combinations<Vertex>(nonTerminals, i)) // { // foreach (var nodes in (from a in terminalCombinations // select new HashSet<Vertex>(a.Union(nonTerminalSet)))) // { // var edges = nodes.SelectMany(graph.GetEdgesForVertex) // .Distinct() // .Where(x => x.WhereOne(y => !nodes.Contains(y))); // GRBLinExpr expression = 0; // foreach (var edge in edges) // expression.AddTerm(1, edgeVars[edge]); // model.AddConstr(expression >= 1.0, "subset_" + conNr); // conNr++; // } // nonTerminalSetsDone++; // if (nonTerminalSetsDone % 100 == 0) // Console.Write("\rRunning LP. Creating constraints... {0}/{1} ({2:0.000}%)\r", nonTerminalSetsDone, nonTerminalSets, nonTerminalSetsDone * 100.0 / nonTerminalSets); // } //} // Solve the LP model Console.Write("\rRunning LP. Creating objective & updating... \r"); GRBLinExpr objective = new GRBLinExpr(); for (int i = 0; i < graph.NumberOfEdges; i++) objective.AddTerm(graph.Edges[i].Cost, variables[i]); model.SetObjective(objective, GRB.MINIMIZE); Console.Write("\rRunning LP. Tuning... \r"); model.Tune(); Debug.WriteLine("Presolve called."); model.Presolve(); Console.Write("\rRunning LP. Solving... \r"); Debug.WriteLine("Optimize called."); model.Optimize(); Graph solution = graph.Clone(); HashSet<Edge> includedEdges = new HashSet<Edge>(); for (int i = 0; i < solution.NumberOfEdges; i++) { var value = variables[i].Get(GRB.DoubleAttr.X); if (value == 1) includedEdges.Add(solution.Edges[i]); } foreach (var edge in solution.Edges.ToList()) if (!includedEdges.Contains(edge)) solution.RemoveEdge(edge); Console.Write("\r \r"); return solution; }
static void Main() { try { // Create environment GRBEnv env = new GRBEnv(); // Create a new model GRBModel model = new GRBModel(env); // Create variables double lb = 0.0, ub = 1.0; GRBVar x = model.AddVar(lb, ub, 0.0, GRB.CONTINUOUS, "x"); GRBVar y = model.AddVar(lb, ub, 0.0, GRB.CONTINUOUS, "y"); GRBVar z = model.AddVar(lb, ub, 0.0, GRB.CONTINUOUS, "z"); // Set objective for y model.SetObjective(-y); // Add piecewise-linear objective functions for x and z int npts = 101; double[] ptu = new double[npts]; double[] ptf = new double[npts]; double[] ptg = new double[npts]; for (int i = 0; i < npts; i++) { ptu[i] = lb + (ub - lb) * i / (npts - 1); ptf[i] = f(ptu[i]); ptg[i] = g(ptu[i]); } model.SetPWLObj(x, ptu, ptf); model.SetPWLObj(z, ptu, ptg); // Add constraint: x + 2 y + 3 z <= 4 model.AddConstr(x + 2 * y + 3 * z <= 4.0, "c0"); // Add constraint: x + y >= 1 model.AddConstr(x + y >= 1.0, "c1"); // Optimize model as an LP model.Optimize(); Console.WriteLine("IsMIP: " + model.IsMIP); Console.WriteLine(x.VarName + " " + x.X); Console.WriteLine(y.VarName + " " + y.X); Console.WriteLine(z.VarName + " " + z.X); Console.WriteLine("Obj: " + model.ObjVal); Console.WriteLine(); // Negate piecewise-linear objective function for x for (int i = 0; i < npts; i++) { ptf[i] = -ptf[i]; } model.SetPWLObj(x, ptu, ptf); // Optimize model as a MIP model.Optimize(); Console.WriteLine("IsMIP: " + model.IsMIP); Console.WriteLine(x.VarName + " " + x.X); Console.WriteLine(y.VarName + " " + y.X); Console.WriteLine(z.VarName + " " + z.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); } }
// return false if not enough tick data public bool TryGetTickRecommendations() { var env = new GRBEnv(); env.LogToConsole = 0; var model = new GRBModel(env); var userTickData = new List <UserTickData>(); foreach (var history in _tickHistories) { var userNum = _tickHistories.IndexOf(history); // todo // todo time delta if (history.GetValidInbetweenCount < 5) { Logger.Warn($"Not enough inbetweens for {userNum}, has {history.GetValidInbetweenCount}"); return(false); } history.GetStatistics(out float average, out float std); var userTick = new UserTickData { LastTickSeconds = history.LastTickSeconds, // this needs to be close enough to a min tick time AvgDelta = average, StdDelta = std, TimeFrame = FindTicksInSeconds }; userTickData.Add(userTick); GRBVar avgVar = model.AddVar(0, double.PositiveInfinity, 0, GRB.CONTINUOUS, $"avg_u{userNum}"); userTick.RecommendedAvgVar = avgVar; } // variant 1: make them sync // variant 2: find a possible intersection point??? perhaps this is already handled by the prep time thing var stdOffsetFactor = .5f; var meanDeltaDistance = .1f; GRBLinExpr minimizeValue = 0; // finde kleinsten gemeinsamen nenner for (int userNum = 0; userNum < userTickData.Count; userNum++) { var userInfo = userTickData[userNum]; model.AddConstr(userInfo.RecommendedAvgVar <= userInfo.AvgDelta + userInfo.StdDelta * stdOffsetFactor, $"ubound_avg_u{userNum}"); model.AddConstr(userInfo.RecommendedAvgVar >= userInfo.AvgDelta - userInfo.StdDelta * stdOffsetFactor, $"lbound_avg_u{userNum}"); GRBVar absAvgDelta = model.AddVar(0, double.PositiveInfinity, 0, GRB.CONTINUOUS, $"abs_avg_delta_u{userNum}"); model.AddConstr(userInfo.RecommendedAvgVar - userInfo.AvgDelta <= absAvgDelta, $"abs_avg_delta_r-a_u{userNum}"); model.AddConstr(userInfo.AvgDelta - userInfo.RecommendedAvgVar <= absAvgDelta, $"abs_avg_delta_a-r_u{userNum}"); minimizeValue += absAvgDelta; for (int otherNum = userNum + 1; otherNum < userTickData.Count; otherNum++) { var otherInfo = userTickData[otherNum]; GRBVar interval = model.AddVar(0, double.PositiveInfinity, 0, GRB.CONTINUOUS, $"interval_u{userNum}_u{otherNum}"); GRBVar smaller; GRBVar larger; if (userInfo.AvgDelta <= otherInfo.AvgDelta) { smaller = userInfo.RecommendedAvgVar; larger = otherInfo.RecommendedAvgVar; } else { smaller = otherInfo.RecommendedAvgVar; larger = userInfo.RecommendedAvgVar; } model.AddConstr(interval * smaller <= larger + meanDeltaDistance, $"interval_u{userNum}_u{otherNum}_1"); model.AddConstr(interval * smaller >= larger - meanDeltaDistance, $"interval_u{userNum}_u{otherNum}_2"); } } model.SetObjective(minimizeValue); model.ModelSense = GRB.MINIMIZE; model.Update(); model.Optimize(); // if didn't a solution, cancel if (model.Status != GRB.Status.OPTIMAL) { Logger.Warn($"Didn't find solution to time conditions. Gurobi status: {model.Status}"); // todo return(false); } foreach (var userInfo in userTickData) { userInfo.RecommendedAvg = (float)userInfo.RecommendedAvgVar.X; } // (1)necessaryTick from a transition // or!: (3)the largest transition ==> this for now because it's easiest // or!: (2)the most convienient point everyone can convieniently hit var necessaryTick = 2 * userTickData.Max(userInfo => userInfo.RecommendedAvg); userTickData.ForEach(userTick => userTick.TimeFrame = necessaryTick); foreach (var userInfo in userTickData) { model.Reset(); minimizeValue = 0; // do three times // check if any of the last hit the necessary constraint // or the one before // or the one before // last tick for (int i = 0; i < userInfo.AvgNumTicksInTimeFrame; i++) { GRBVar tickVar = model.AddVar(0, double.PositiveInfinity, 0, GRB.CONTINUOUS, $"tick_t{i}"); userInfo.RecommendedTickVars.Add(tickVar); } for (int i = 0; i < userInfo.RecommendedTickVars.Count; i++) { var tick = userInfo.RecommendedTickVars[i]; if (i == 0) { GRBVar interval = model.AddVar(0, double.PositiveInfinity, 0, GRB.CONTINUOUS, $"interval_to_last_tick"); // soft constraint! model.AddConstr( tick - userInfo.LastTickSeconds <= interval * (userInfo.RecommendedAvg + userInfo.StdDelta * stdOffsetFactor), $"interval_to_last_tick_uconstraint"); model.AddConstr( tick - userInfo.LastTickSeconds >= interval * (userInfo.RecommendedAvg - userInfo.StdDelta * stdOffsetFactor), $"interval_to_last_tick_lconstraint"); } else if (i < userInfo.AvgNumTicksInTimeFrame - 1) { var nextTick = userInfo.RecommendedTickVars[i + 1]; model.AddConstr( nextTick - tick <= userInfo.RecommendedAvg + userInfo.StdDelta * stdOffsetFactor, $"delta{i}_uconstraint"); model.AddConstr( nextTick - tick >= userInfo.RecommendedAvg - userInfo.StdDelta * stdOffsetFactor, $"delta{i}_lconstraint"); } } // delta distance minimization minimizeValue = MinimizeDeltaDistance(model, minimizeValue, userInfo.RecommendedTickVars[userInfo.AvgNumTicksInTimeFrame - 1], necessaryTick, "lastTickToNecessary"); if (userInfo.AvgNumTicksInTimeFrame > 1) { minimizeValue = MinimizeDeltaDistance(model, minimizeValue, userInfo.RecommendedTickVars[userInfo.AvgNumTicksInTimeFrame - 2], necessaryTick, "preLastTickToNecessary"); } if (userInfo.AvgNumTicksInTimeFrame > 2) { minimizeValue = MinimizeDeltaDistance(model, minimizeValue, userInfo.RecommendedTickVars[userInfo.AvgNumTicksInTimeFrame - 3], necessaryTick, "prePreLastTickToNecessary"); } model.SetObjective(minimizeValue); model.ModelSense = GRB.MINIMIZE; model.Update(); model.Optimize(); if (model.Status != GRB.Status.OPTIMAL) { Logger.Warn($"Didn't find solution for user. Gurobi status: {model.Status}"); return(false); } userInfo.RecommendedTicks = userInfo.RecommendedTickVars.Select(var => (float)var.X).ToList(); } LastNecessaryTick = necessaryTick; _lastCalculatedTickData = userTickData; return(true); }
public GurobiSolver3(Crossword crossword) { var wordLengthHistogram = new Dictionary <int, double>() { { 3, 18 }, { 4, 24 }, { 5, 20 }, { 6, 18 }, { 7, 12 }, { 8, 4 }, { 9, 4 }, }; const int maxWordLength = 9; int sizeY = crossword.Grid.GetLength(0); int sizeX = crossword.Grid.GetLength(1); 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); // 0 = letter, 1 = question GRBVar[,] fields = new GRBVar[sizeY, sizeX]; // 0 = right, 1 = down GRBVar[,] questionType = new GRBVar[sizeY, sizeX]; for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { // create a var for every non-blocked field if (!(crossword.Grid[y, x] is Blocked)) { fields[y, x] = m.AddVar(0, 1, 0, GRB.BINARY, "Field" + x + "_" + y); questionType[y, x] = m.AddVar(0, 1, 0, GRB.BINARY, "QType" + x + "_" + y); } } } GRBLinExpr allFieldsSum = new GRBLinExpr(); // All non-question fields have to belong to a word // E.g. if a question points right, only lengths 3 to 9 are allowed 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 + 3 < sizeX && !crossword.HasBlock(y, x, y, x + 3)) { // for right: if [0,0] is question, [0,1..3] must not be question var totalQuestionsHorizontal = fields[y, x + 1] + fields[y, x + 2] + fields[y, x + 3]; m.AddConstr(fields[y, x] + (1 - questionType[y, x]) - 1 <= 1 - fields[y, x + 1], "MinWordLength3" + y + "_" + x + "_right1"); m.AddConstr(fields[y, x] + (1 - questionType[y, x]) - 1 <= 1 - fields[y, x + 2], "MinWordLength3" + y + "_" + x + "_right2"); m.AddConstr(fields[y, x] + (1 - questionType[y, x]) - 1 <= 1 - fields[y, x + 3], "MinWordLength3" + y + "_" + x + "_right3"); } else { noQuestionToTheRightAllowed = true; } // for down: if (y + 3 < sizeY && !crossword.HasBlock(y, x, y + 3, x)) { var totalQuestionsVertical = fields[y + 1, x] + fields[y + 2, x] + fields[y + 3, x]; m.AddConstr(fields[y, x] + questionType[y, x] - 1 <= 1 - fields[y + 1, x], "MinWordLength3" + y + "_" + x + "_down1"); m.AddConstr(fields[y, x] + questionType[y, x] - 1 <= 1 - fields[y + 2, x], "MinWordLength3" + y + "_" + x + "_down2"); m.AddConstr(fields[y, x] + questionType[y, x] - 1 <= 1 - fields[y + 3, x], "MinWordLength3" + y + "_" + x + "_down3"); } else { noQuestionTowardsDownAllowed = true; } if (noQuestionToTheRightAllowed && noQuestionTowardsDownAllowed) { m.AddConstr(fields[y, x] == 0, "NoQuestionAllowed" + 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 if (x + maxWordLength + 1 < sizeX && !crossword.HasBlock(y, x, y, x + maxWordLength + 1)) { // for right: if [0,0] is question, [0,1..maxLength+1] must have at least another question field var allHorizontalFields = new GRBLinExpr(); for (int xi = 1; xi <= maxWordLength + 1; xi++) { allHorizontalFields += fields[y, x + xi]; } m.AddConstr(fields[y, x] + (1 - questionType[y, x]) - 1 <= allHorizontalFields, "MaxLengthHorizontal" + y + "_" + x); } if (y + maxWordLength + 1 < sizeY && !crossword.HasBlock(y, x, y + maxWordLength + 1, x)) { // for down: var allVerticalFields = new GRBLinExpr(); for (int yi = 1; yi <= maxWordLength + 1; yi++) { allVerticalFields += fields[y + yi, x]; } m.AddConstr(fields[y, x] + questionType[y, x] - 1 <= allVerticalFields, "MaxLengthVertical" + y + "_" + x); } } } // Does a field belong to zero, one or two questions? var partOfAWord = new GRBLinExpr[sizeY, sizeX, 2]; for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { // this constraint doesn't work for [0,0] if ((x == 0 && y == 0) || crossword.HasBlock(y, x)) { continue; } // does this field have a question to the left? /*var attachedToHorizontalQuestion = new GRBLinExpr(); * for (int l = 0; l < maxWordLength; l++) * { * if (x - l - 1 < 0) continue; * var attachedToHorizontalQuestionSpecificLength = m.AddVar(0, 1, 0, GRB.BINARY, "varAttachedToHorizontalQuestionLength" + l + "_" + y + "_" + x); * // If the first field is a question and points to the right, and no letters inbetween are questions * var isQuestionAndPointsRight = fields[y, x - l - 1] + (1 - questionType[y, x - l - 1]); * var allHorizontalFields = new GRBLinExpr(); * for (int xi = 0; xi <= l; xi++) * allHorizontalFields += fields[y, x - xi]; * m.AddConstr(attachedToHorizontalQuestionSpecificLength >= isQuestionAndPointsRight - 1 - allHorizontalFields); * for (int xi = 0; xi <= l; xi++) m.AddConstr(attachedToHorizontalQuestionSpecificLength <= 1 - fields[y, x - xi]); * m.AddConstr(attachedToHorizontalQuestionSpecificLength <= fields[y, x - l - 1]); * m.AddConstr(attachedToHorizontalQuestionSpecificLength <= 1 - questionType[y, x - l - 1]); * //m.AddConstr(attachedToHorizontalQuestionSpecificLength <= isQuestionAndPointsRight * 0.5); * //m.AddConstr(attachedToHorizontalQuestionSpecificLength <= 1 - allHorizontalFields * (1d / (l + 1))); * attachedToHorizontalQuestion += attachedToHorizontalQuestionSpecificLength; * }*/ // RETRY 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]); var questionsInbetween = new GRBLinExpr(); for (int xi = 0; xi < len; xi++) { questionsInbetween += fields[y, x - xi]; } m.AddConstr(attachedToHorizontalQuestion >= isQuestionAndPointsRight - 1 - questionsInbetween); // 0 IF first question is not pointing right OR there is no question to the left // firstQuestion ==> total fields < 2 m.AddConstr(attachedToHorizontalQuestion <= questionsInbetween + (1 - fields[y, x - len]) + 1 - questionType[y, x - len]); // 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); } // does this field have a question towards down? /*var attachedToVerticalQuestion = new GRBLinExpr(); * for (int l = 0; l < maxWordLength; l++) * { * if (y - l - 1 < 0) continue; * var attachedToVerticalQuestionSpecificLength = m.AddVar(0, 1, 0, GRB.BINARY, "varAttachedToVerticalQuestionLength" + l + "_" + y + "_" + x); * // If the first field is a question and points to the right, and no letters inbetween are questions * var isQuestionAndPointsDown = fields[y - l - 1, x] + questionType[y - l - 1, x]; * var allVerticalFields = new GRBLinExpr(); * for (int yi = 0; yi <= l; yi++) * allVerticalFields += fields[y - yi, x]; * m.AddConstr(attachedToVerticalQuestionSpecificLength >= isQuestionAndPointsDown - 1 - allVerticalFields); * for (int yi = 0; yi <= l; yi++) m.AddConstr(attachedToVerticalQuestionSpecificLength <= 1 - fields[y - yi, x]); * m.AddConstr(attachedToVerticalQuestionSpecificLength <= fields[y - l - 1, x]); * m.AddConstr(attachedToVerticalQuestionSpecificLength <= questionType[y - l - 1, x]); * //m.AddConstr(attachedToVerticalQuestionSpecificLength <= isQuestionAndPointsDown * 0.5); * //m.AddConstr(attachedToVerticalQuestionSpecificLength <= 1 - allVerticalFields * (1d / (l + 1))); * attachedToVerticalQuestion += attachedToVerticalQuestionSpecificLength; * }*/ 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]; var questionsInbetween = new GRBLinExpr(); for (int yi = 0; yi < len; yi++) { questionsInbetween += fields[y - yi, x]; } m.AddConstr(attachedToVerticalQuestion >= isQuestionAndPointsDown - 1 - questionsInbetween); m.AddConstr(attachedToVerticalQuestion <= questionsInbetween + (1 - fields[y - len, x]) + 1 - (1 - questionType[y - len, x])); // the first question but DOESNT look down } 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); } var c = m.AddConstr(attachedToHorizontalQuestion + attachedToVerticalQuestion >= 1 - fields[y, x], "AttachedToQuestionConstraint_" + y + "_" + x); //c.Lazy = 1; partOfAWord[y, x, 0] = attachedToHorizontalQuestion; partOfAWord[y, x, 1] = attachedToVerticalQuestion; } } // 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 - 3; y < sizeY; y++) { for (int x = sizeX - 3; x < sizeX; x++) { if (!crossword.HasBlock(y, x)) { m.AddConstr(fields[y, x] == 0); } } } // 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"); // dead fields var uncrossedLetters = new GRBVar[sizeY, sizeX]; var uncrossedLettersPenalty = new GRBLinExpr(); for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { if ((x >= 1 || y >= 1) && !crossword.HasBlock(y, x)) { uncrossedLetters[y, x] = m.AddVar(0, 1, 0, GRB.BINARY, "isUncrossedLetter" + y + "_" + x); m.AddConstr(uncrossedLetters[y, x] <= partOfAWord[y, x, 0] + partOfAWord[y, x, 1]); // if 0 ==> 0 NECESSARY? m.AddConstr(uncrossedLetters[y, x] <= 2 - partOfAWord[y, x, 0] - partOfAWord[y, x, 1]); // if 2 ==> 0 m.AddConstr(uncrossedLetters[y, x] <= 1 - fields[y, x]); // if it's a question it can't be a dead field m.AddConstr(uncrossedLetters[y, x] >= partOfAWord[y, x, 0] - partOfAWord[y, x, 1] - fields[y, x]); // horizontal XOR vertical m.AddConstr(uncrossedLetters[y, x] >= partOfAWord[y, x, 1] - partOfAWord[y, x, 0] - fields[y, x]); uncrossedLettersPenalty += uncrossedLetters[y, x]; } } } // penalty for nearby uncrossed letters 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 (x >= 1 && y >= 1 && !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); } if (hbx) { m.AddConstr(isDeadArea >= uncrossedLetters[y, x] + uncrossedLetters[y, x - 1] - 1); } m.AddConstr(isDeadArea <= uncrossedLetters[y, x]); if (hby && hbx) { m.AddConstr(isDeadArea <= uncrossedLetters[y - 1, x] + uncrossedLetters[y, x - 1]); } else if (hby) { m.AddConstr(isDeadArea <= uncrossedLetters[y - 1, x]); } else if (hbx) { m.AddConstr(isDeadArea <= uncrossedLetters[y, x - 1]); } deadFieldPenalty += isDeadArea; } } } // as many partOfAWord == 2 as possible /*var manyCrossedWords = new GRBLinExpr(); * for (int y = 0; y < sizeY; y++) * for (int x = 0; x < sizeX; x++) * manyCrossedWords += partOfAWord[y, x];*/ // ideal histogram comparison //var wordHistogramDifferences = new GRBLinExpr(); foreach (var wl in wordLengthHistogram.Keys) { /*var varDiffInput = m.AddVar(-sizeX * sizeY / 3, sizeX * sizeY / 3, 0, GRB.INTEGER, "varDiffInput" + wl); * m.AddConstr(varDiffInput == (wordLengthHistogram[wl] - lengths[wl])); * var varDiffRes = m.AddVar(0, sizeX * sizeY / 3, 0, GRB.INTEGER, "varDiff" + wl); * m.AddGenConstrAbs(varDiffRes, varDiffInput, "diffGenConstr" + wl); * wordHistogramDifferences += varDiffRes;*/ int histogramTolerance = Math.Max(1, (int)(wordLengthHistogram[wl] * 0.2 * wordLengthRatio)); //m.AddConstr(wordLengthHistogram[wl] - lengths[wl] >= -histogramTolerance); //m.AddConstr(wordLengthHistogram[wl] - lengths[wl] <= histogramTolerance); } // 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 = 2; 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)) { continue; } clusterTotal += fields[y + i, x + j]; ct++; } } if (ct >= 3) { var varClusterTotalPenalty = m.AddVar(0, 1, 0, GRB.BINARY, "varClusterTotalPenalty" + y + "_" + x); // 0-1 = good, 2-4 = bad 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(deadFieldPenalty + clusterPenalty, GRB.MINIMIZE); m.SetCallback(new GRBMipSolCallback(crossword, fields, questionType, null)); m.Optimize(); m.ComputeIIS(); m.Write("model.ilp"); m.Dispose(); env.Dispose(); }
public static void build_initial_model(bool lp_relax) { env = new GRBEnv(true); env.Set("LogFile", "Recoloracao.log"); env.Set(GRB.IntParam.LogToConsole, 0); env.Start(); model = new GRBModel(env); model.ModelName = "Recoloracao"; model.Set(GRB.IntParam.Threads, 1); model.Set(GRB.IntParam.Method, 1); model.Set(GRB.DoubleParam.TimeLimit, 1800); X = new GRBVar[input.nVertices, input.nCores]; var obj = new GRBLinExpr(); for (int i = 0; i < input.nVertices; i++) { for (int j = 0; j < input.nCores; j++) { string nome = "X_ " + i.ToString() + "_c " + j.ToString(); if (lp_relax) { X[i, j] = model.AddVar(0.0, 1.0, 1.0, GRB.CONTINUOUS, nome); } else { X[i, j] = model.AddVar(0.0, 1.0, 1.0, GRB.BINARY, nome); } if (input.caminhoColorido[i] != j + 1) { obj.AddTerm(1, X[i, j]); } } } model.SetObjective(obj, GRB.MINIMIZE); // Restrição 1 for (int i = 0; i < input.nVertices; i++) { GRBLinExpr soma = new GRBLinExpr(); for (int c = 0; c < input.nCores; c++) { soma.AddTerm(1.0, X[i, c]); } model.AddConstr(soma, GRB.EQUAL, 1, "Cor vértice" + i); } // Restrição 2 for (int p = 0; p < input.nVertices - 2; p++) { for (int r = p + 2; r < input.nVertices; r++) { for (int q = p + 1; q < r; q++) { for (int k = 0; k < input.nCores; k++) { model.AddConstr(X[p, k] - X[q, k] + X[r, k], GRB.LESS_EQUAL, 1, "p" + p + "-q" + q + "-r" + r + "-k" + k); } } } } }
void BuildFeasibleSolutionModel() { _env = new GRBEnv("SolutionLog.log"); _env.Set(GRB.DoubleParam.MIPGap, 0.0); _env.Set(GRB.DoubleParam.TimeLimit, 500); _grbModel = new GRBModel(_env); //决策变量 foreach (Node n in Data.NodeSet) { n.Result_GenerateFlow = _grbModel.AddVar(0.0, GRB.INFINITY, 0.0, GRB.CONTINUOUS, "g_" + n.ID); } foreach (Arc a in Data.ArcSet) { a.Result_FlowF = _grbModel.AddVar(0.0, GRB.INFINITY, 0.0, GRB.CONTINUOUS, "fF_" + a.FromNode.ID + "_" + a.ToNode.ID); a.Result_FlowR = _grbModel.AddVar(0.0, GRB.INFINITY, 0.0, GRB.CONTINUOUS, "fR_" + a.FromNode.ID + "_" + a.ToNode.ID); } _grbModel.Update(); //目标函数 GRBLinExpr expr1 = 0; foreach (Node n in Data.NodeSet) { expr1 += n.IsServerLocationSelected * Data.ServerInstalationFee; } GRBLinExpr expr2 = 0; foreach (Arc a in Data.ArcSet) { expr2 += (a.Result_FlowF + a.Result_FlowR) * Data.FlowFeePerUnit; } _grbModel.SetObjective(expr1 + expr2, GRB.MINIMIZE); //约束条件 foreach (Node n in Data.NodeSet) { _grbModel.AddConstr(n.Result_GenerateFlow <= n.IsServerLocationSelected * Data.M, "ct1_" + n.ID); } foreach (Node n in Data.NodeSet) { GRBLinExpr sum1 = 0; GRBLinExpr sum2 = 0; GRBLinExpr sum3 = 0; GRBLinExpr sum4 = 0; foreach (Arc a in n.ArcSet) { if (a.ToNode == n)//进 { sum1 += a.Result_FlowF; sum3 += a.Result_FlowR; } else//出 { sum2 += a.Result_FlowR; sum4 += a.Result_FlowF; } } _grbModel.AddConstr(n.Result_GenerateFlow + sum1 + sum2 == n.Demand + sum3 + sum4, "ct2_" + n.ID); } foreach (Arc a in Data.ArcSet) { _grbModel.AddConstr(a.Result_FlowF + a.Result_FlowR <= a.Capacity, "ct3_" + a.FromNode.ID + "_" + a.ToNode.ID); } }
/// <summary> /// Method called when a process token executes the step. /// </summary> public ExitType Execute(IStepExecutionContext context) { IState _timenow = _propTimenow.GetState(context); double timenow = Convert.ToDouble(_timenow.StateValue); IState _salida = _propSalida.GetState(context); double salida = Convert.ToDouble(_salida.StateValue); IState _aux = _propAux.GetState(context); double aux = Convert.ToDouble(_aux.StateValue); SerializarElement sr = new SerializarElement(); if (File.Exists(sr.SerializationFile)) { Vect v = sr.deserializa(); vectores = sr.deserializa(); vectores.MipYc = v.MipYc; vectores.MipYv = v.MipYv; vectores.MipTc = v.MipTc; vectores.MipTv = v.MipTv; //Dinamico vectores.Din1 = v.Din1; vectores.DesCam = v.DesCam; vectores.Fila = v.Fila; //LP vectores.TCV = v.TCV; vectores.TCC = v.TCC; vectores.TCj = v.TCj; vectores.TDi = v.TDi; vectores.Destij = v.Destij; vectores.Dj = v.Dj; vectores.Uj = v.Uj; vectores.Ui = v.Ui; vectores.RLi = v.RLi; vectores.RUi = v.RUi; vectores.PlYc = v.PlYc; vectores.PlYv = v.PlYv; vectores.PlTc = v.PlTc; vectores.PlTv = v.PlTv; vectores.PlTcmalo = v.PlTcmalo; vectores.Mine = v.Mine; vectores.Mineralocado = v.Mineralocado; vectores.Lastrealocado = v.Lastrealocado; } //i Botaderos. j Palas. k Camiones. double[,] Din12 = (double[, ])vectores.Din1.Clone(); double[,] Tij = (double[, ])vectores.PlTc.Clone();//I Tonelaje por turno double[,] xij = new double[30, 20]; //I Tonelaje cumplido hasta el momento de activación del dinámico double[,] yij = new double[30, 20]; //Tonelaje requerido para alcazar R double[,] Rij = new double[30, 20]; //Porcentaje de cumplimienteo del tonelaje double[,] dij = new double[30, 20]; //Desviación del porcentaje de cumplimiento ideal en el momento de activación double[,] Mij = new double[30, 20]; //Demanda de camiones por ruta double[,] rij = new double[30, 20]; //I Matriz de tiempos de viajes double[] tk = new double[81]; //I Tiempo que le toma al camión k llegar al botadero/chancador al que va (si ya está en un botadero este tiempo es 0) double[] dk = new double[81]; //I Tiempo esperado de espera del camión k en el botadero/chancador al que va double[] ej = new double[30]; //I Tiempo promedio de descarga en el botadero j double[] Di = new double[20]; //Demanda de camiones por pala (int?) double[] Li = new double[20]; //I Tiempo promedio de carga en la pala i double[] Ni = new double[20]; //I Número de camiones en la pala i (int?) double[] Ei = new double[20]; //I Camiones en ruta a la pala i (int?) double[] Sk = new double[81]; //I Arreglo de variables binarias que indican si el camión tiene una tarea asignada int[] Bk = new int[81]; //Botadero al que está llendo el camión k int numcam = 81; //Número total de camiones double capacidad = 300; //Capacidad de los camiones int numPalas = 20; //Palas activas? int numBotaderos = 30; //Botaderos o chancador activos? double R = 0; //Se cálcula el porcentaje de cumplimiento de cuota for (int i = 0; i < numBotaderos; i++) { for (int j = 0; j < numPalas; j++) { if (Tij[i, j] != 0) { Rij[i, j] = xij[i, j] / Tij[i, j]; R = R + Rij[i, j]; } } } //Se calcula de déficit o superávit R = R / (numPalas * numBotaderos); for (int i = 0; i < numBotaderos; i++) { for (int j = 0; j < numPalas; j++) { dij[i, j] = Rij[i, j] - R; } } //Se calcula la demanda adeudada para alcanzar R double mij_aux; int mij; for (int i = 0; i < numBotaderos; i++) { for (int j = 0; j < numPalas; j++) { yij[i, j] = R * Tij[i, j] - xij[i, j]; mij_aux = yij[i, j] / capacidad; mij = Convert.ToInt32(mij_aux); Mij[i, j] = mij + 1; } } double DTotal = 0; double di; for (int j = 0; j < numPalas; j++) { di = 0; for (int i = 0; i < numPalas; i++) { di = Mij[i, j] + di; } Di[j] = di; DTotal = DTotal + Di[j]; } //En teoría se debería hacer un chequeo para que la demanda total de camiones no supere //el total disponible. De ocurrir, se deben limitar los flujos del PL (*). //Criterio de asignación de camiones //Se crea el arreglo Wik que contiene los tiempos que demora al camion k llegar a ser //atendido por la pala i. El tamaño de este arreglo depende de los camiones disponibles. double[,] Wik = new double[numPalas, numcam];//Matriz de tiempos esperados del camión k para ser atendido por la pala i for (int k = 0; k < numcam; k++) { if (Sk[k] != 0) //Sólo para los camiones sin tareas asignadas { for (int i = 0; i < numPalas; i++) { Wik[i, k] = Li[i] * (Ni[i] + Ei[i]) - (tk[k] + dk[k] + ej[Bk[k]] + rij[Bk[k], i]); } } } //Modelo GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); model.ModelName = "Asignación Dinámica"; GRBVar[,] X = new GRBVar[numPalas, numcam]; //Binaria que define si el camión k se asigna a la pala i for (int i = 0; i < numPalas; i++) { for (int k = 0; k < numcam; k++) { X[i, k] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "X" + i + "_" + k); } } model.Update(); //Restricciones for (int k = 0; k < numcam; k++) { GRBLinExpr suma_Xik = 0; for (int i = 0; i < numPalas; i++) { suma_Xik = suma_Xik + X[i, k]; } model.AddConstr(suma_Xik, GRB.LESS_EQUAL, Sk[k], "S" + k); } for (int i = 0; i < numPalas; i++) { GRBLinExpr suma_Xik = 0; for (int k = 0; k < numcam; k++) { suma_Xik = suma_Xik + X[i, k]; } model.AddConstr(suma_Xik, GRB.GREATER_EQUAL, Di[i], "D" + i); } model.Update(); GRBLinExpr FO = 0; for (int i = 0; i < numPalas; i++) { for (int k = 0; k < numcam; k++) { FO = FO + Wik[i, k] * X[i, k]; } } model.SetObjective(FO, GRB.MINIMIZE); model.Update(); model.Optimize(); sr.serializa(vectores); sr.closeStream(); return(ExitType.FirstExit); }
static void Main() { try { GRBEnv env = new GRBEnv("qp.log"); GRBModel model = new GRBModel(env); // Create variables GRBVar x = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "x"); GRBVar y = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "y"); GRBVar z = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "z"); // Integrate new variables model.Update(); // Set objective GRBQuadExpr obj = x*x + x*y + y*y + y*z + z*z; model.SetObjective(obj); // Add constraint: x + 2 y + 3 z >= 4 model.AddConstr(x + 2 * y + 3 * z >= 4.0, "c0"); // Add constraint: x + y >= 1 model.AddConstr(x + y >= 1.0, "c1"); // Optimize model model.Optimize(); Console.WriteLine(x.Get(GRB.StringAttr.VarName) + " " + x.Get(GRB.DoubleAttr.X)); Console.WriteLine(y.Get(GRB.StringAttr.VarName) + " " + y.Get(GRB.DoubleAttr.X)); Console.WriteLine(z.Get(GRB.StringAttr.VarName) + " " + z.Get(GRB.DoubleAttr.X)); Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal) + " " + obj.Value); // Change variable types to integer x.Set(GRB.CharAttr.VType, GRB.INTEGER); y.Set(GRB.CharAttr.VType, GRB.INTEGER); z.Set(GRB.CharAttr.VType, GRB.INTEGER); // Optimize model model.Optimize(); Console.WriteLine(x.Get(GRB.StringAttr.VarName) + " " + x.Get(GRB.DoubleAttr.X)); Console.WriteLine(y.Get(GRB.StringAttr.VarName) + " " + y.Get(GRB.DoubleAttr.X)); Console.WriteLine(z.Get(GRB.StringAttr.VarName) + " " + z.Get(GRB.DoubleAttr.X)); Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal) + " " + obj.Value); // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { GRBEnv env = new GRBEnv("qp.log"); GRBModel model = new GRBModel(env); // Create variables GRBVar x = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "x"); GRBVar y = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "y"); GRBVar z = model.AddVar(0.0, 1.0, 0.0, GRB.CONTINUOUS, "z"); // Integrate new variables model.Update(); // Set objective GRBQuadExpr obj = x * x + x * y + y * y + y * z + z * z + 2 * x; model.SetObjective(obj); // Add constraint: x + 2 y + 3 z >= 4 model.AddConstr(x + 2 * y + 3 * z >= 4.0, "c0"); // Add constraint: x + y >= 1 model.AddConstr(x + y >= 1.0, "c1"); // Optimize model model.Optimize(); Console.WriteLine(x.Get(GRB.StringAttr.VarName) + " " + x.Get(GRB.DoubleAttr.X)); Console.WriteLine(y.Get(GRB.StringAttr.VarName) + " " + y.Get(GRB.DoubleAttr.X)); Console.WriteLine(z.Get(GRB.StringAttr.VarName) + " " + z.Get(GRB.DoubleAttr.X)); Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal) + " " + obj.Value); // Change variable types to integer x.Set(GRB.CharAttr.VType, GRB.INTEGER); y.Set(GRB.CharAttr.VType, GRB.INTEGER); z.Set(GRB.CharAttr.VType, GRB.INTEGER); // Optimize model model.Optimize(); Console.WriteLine(x.Get(GRB.StringAttr.VarName) + " " + x.Get(GRB.DoubleAttr.X)); Console.WriteLine(y.Get(GRB.StringAttr.VarName) + " " + y.Get(GRB.DoubleAttr.X)); Console.WriteLine(z.Get(GRB.StringAttr.VarName) + " " + z.Get(GRB.DoubleAttr.X)); Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal) + " " + obj.Value); // Dispose of model and env model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }
static void Main() { try { // Create environment GRBEnv env = new GRBEnv(); // Create a new m GRBModel m = new GRBModel(env); double lb = 0.0, ub = GRB.INFINITY; GRBVar x = m.AddVar(lb, ub, 0.0, GRB.CONTINUOUS, "x"); GRBVar y = m.AddVar(lb, ub, 0.0, GRB.CONTINUOUS, "y"); GRBVar u = m.AddVar(lb, ub, 0.0, GRB.CONTINUOUS, "u"); GRBVar v = m.AddVar(lb, ub, 0.0, GRB.CONTINUOUS, "v"); // Set objective m.SetObjective(2 * x + y, GRB.MAXIMIZE); // Add linear constraint m.AddConstr(u + 4 * v <= 9, "l1"); // Approach 1) PWL constraint approach double intv = 1e-3; double xmax = Math.Log(9.0); int len = (int)Math.Ceiling(xmax / intv) + 1; double[] xpts = new double[len]; double[] upts = new double[len]; for (int i = 0; i < len; i++) { xpts[i] = i * intv; upts[i] = f(i * intv); } GRBGenConstr gc1 = m.AddGenConstrPWL(x, u, xpts, upts, "gc1"); double ymax = (9.0 / 4.0) * (9.0 / 4.0); len = (int)Math.Ceiling(ymax / intv) + 1; double[] ypts = new double[len]; double[] vpts = new double[len]; for (int i = 0; i < len; i++) { ypts[i] = i * intv; vpts[i] = g(i * intv); } GRBGenConstr gc2 = m.AddGenConstrPWL(y, v, ypts, vpts, "gc2"); // Optimize the model and print solution m.Optimize(); printsol(m, x, y, u, v); // Approach 2) General function constraint approach with auto PWL // translation by Gurobi // restore unsolved state and get rid of PWL constraints m.Reset(); m.Remove(gc1); m.Remove(gc2); m.Update(); GRBGenConstr gcf1 = m.AddGenConstrExp(x, u, "gcf1", ""); GRBGenConstr gcf2 = m.AddGenConstrPow(y, v, 0.5, "gcf2", ""); m.Parameters.FuncPieceLength = 1e-3; // Optimize the model and print solution m.Optimize(); printsol(m, x, y, u, v); // Zoom in, use optimal solution to reduce the ranges and use a smaller // pclen=1e-5 to solve it x.LB = Math.Max(x.LB, x.X - 0.01); x.UB = Math.Min(x.UB, x.X + 0.01); y.LB = Math.Max(y.LB, y.X - 0.01); y.UB = Math.Min(y.UB, y.X + 0.01); m.Update(); m.Reset(); m.Parameters.FuncPieceLength = 1e-5; // Optimize the model and print solution m.Optimize(); printsol(m, x, y, u, v); // Dispose of model and environment m.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); } }