static void Main() { CP cp = new CP(); IIntVar Belgium = cp.IntVar(0, 3); IIntVar Denmark = cp.IntVar(0, 3); IIntVar France = cp.IntVar(0, 3); IIntVar Germany = cp.IntVar(0, 3); IIntVar Netherlands = cp.IntVar(0, 3); IIntVar Luxembourg = cp.IntVar(0, 3); cp.Add(cp.Neq(Belgium, France)); cp.Add(cp.Neq(Belgium, Germany)); cp.Add(cp.Neq(Belgium, Netherlands)); cp.Add(cp.Neq(Belgium, Luxembourg)); cp.Add(cp.Neq(Denmark, Germany)); cp.Add(cp.Neq(France, Germany)); cp.Add(cp.Neq(France, Luxembourg)); cp.Add(cp.Neq(Germany, Luxembourg)); cp.Add(cp.Neq(Germany, Netherlands)); // Search for a solution if (cp.Solve()) { Console.WriteLine("Solution: "); Console.WriteLine("Belgium: " + Names[cp.GetIntValue(Belgium)]); Console.WriteLine("Denmark: " + Names[cp.GetIntValue(Denmark)]); Console.WriteLine("France: " + Names[cp.GetIntValue(France)]); Console.WriteLine("Germany: " + Names[cp.GetIntValue(Germany)]); Console.WriteLine("Netherlands: " + Names[cp.GetIntValue(Netherlands)]); Console.WriteLine("Luxembourg: " + Names[cp.GetIntValue(Luxembourg)]); } }
private void BuildModel() { // Create the decision variables, cost, and the model scene = new IIntVar[numScenes]; for (int s = 0; s < numScenes; s++) { scene[s] = cp.IntVar(0, numScenes - 1); } // Expression representing the global cost idleCost = cp.IntExpr(); // Make the slot-based secondary model IIntVar[] slot = new IIntVar[numScenes]; for (int s = 0; s < numScenes; s++) { slot[s] = cp.IntVar(0, numScenes - 1); } cp.Add(cp.Inverse(scene, slot)); // Loop over all actors, building cost for (int a = 0; a < numActors; a++) { // Expression for the waiting time for this actor IIntExpr actorWait = cp.IntExpr(); // Calculate the first and last slots where this actor plays List <IIntVar> position = new List <IIntVar>(); System.Collections.IEnumerator en = actorInScene[a].GetEnumerator(); while (en.MoveNext()) { position.Add(slot[(int)en.Current]); } IIntExpr firstSlot = cp.Min(position.ToArray()); IIntExpr lastSlot = cp.Max(position.ToArray()); // If an actor is not in a scene, he waits // if he is on set when the scene is filmed for (int s = 0; s < numScenes; s++) { if (!actorInScene[a].Contains(s)) { // not in scene IIntExpr wait = cp.And(cp.Le(firstSlot, slot[s]), cp.Le( slot[s], lastSlot)); actorWait = cp.Sum(actorWait, cp.Prod(sceneDuration[s], wait)); } } // Accumulate the cost of waiting time for this actor idleCost = cp.Sum(idleCost, cp.Prod(actorPay[a], actorWait)); } cp.Add(cp.Minimize(idleCost)); }
// // Matrix operations // static private IIntVar[][] Transpose(IIntVar[][] x) { int m = x.Length; int n = x[0].Length; IIntVar[][] y = new IIntVar[n][]; for (int i = 0; i < n; i++) { y[i] = new IIntVar[m]; for (int j = 0; j < m; j++) { y[i][j] = x[j][i]; } } return(y); }
static private void SolveModel(string filename) { try { CP cp = new CP(); cp.ImportModel(filename); // Force blue color (zero) for France: IIntVar varFrance = cp.GetIIntVar("France"); varFrance.Max = 0; // Search for a solution if (cp.Solve()) { Console.WriteLine("Solution: "); IIntVar[] vars = cp.GetAllIIntVars(); for (int i = 0; i < vars.Length; i++) { Console.WriteLine(vars[i].Name + ": " + Names[cp.GetIntValue(vars[i])]); } } } catch (ILOG.Concert.Exception e) { Console.WriteLine("ERROR:" + e); } }
internal static IIntVar[][][][] Generate4DNumVar(IMPModeler model, int intCount1, int intCount2, int intCount3, int intCount4) { if (intCount1 < 0) { intCount1 = 0; } IIntVar[][][][] x = new IIntVar[intCount1][][][]; for (int i = 0; i < intCount1; i++) { x[i] = new IIntVar[intCount2][][]; for (int j = 0; j < intCount2; j++) { x[i][j] = new IIntVar[intCount3][]; for (int k = 0; k < intCount3; k++) { x[i][j][k] = model.BoolVarArray(intCount4); } } } return(x); }
static private void CreateModel(string filename) { try { CP cp = new CP(); IIntVar Belgium = cp.IntVar(0, 3, "Belgium"); IIntVar Denmark = cp.IntVar(0, 3, "Denmark"); IIntVar France = cp.IntVar(0, 3, "France"); IIntVar Germany = cp.IntVar(0, 3, "Germany"); IIntVar Netherlands = cp.IntVar(0, 3, "Netherlands"); IIntVar Luxembourg = cp.IntVar(0, 3, "Luxembourg"); cp.Add(cp.Neq(Belgium, France)); cp.Add(cp.Neq(Belgium, Germany)); cp.Add(cp.Neq(Belgium, Netherlands)); cp.Add(cp.Neq(Belgium, Luxembourg)); cp.Add(cp.Neq(Denmark, Germany)); cp.Add(cp.Neq(France, Germany)); cp.Add(cp.Neq(France, Luxembourg)); cp.Add(cp.Neq(Germany, Luxembourg)); cp.Add(cp.Neq(Germany, Netherlands)); cp.DumpModel(filename); } catch (ILOG.Concert.Exception e) { Console.WriteLine("ERROR:" + e); } }
static void Main(string[] args) { String filename; if (args.Length > 0) { filename = args[0]; } else { filename = "../../../../examples/data/plant_location.data"; } DataReader data = new DataReader(filename); int nbCustomer = data.Next(); int nbLocation = data.Next(); int[][] cost = new int[nbCustomer][]; for (int c = 0; c < nbCustomer; c++) { cost[c] = new int[nbLocation]; for (int l = 0; l < nbLocation; l++) { cost[c][l] = data.Next(); } } int[] demand = new int[nbCustomer]; int totalDemand = 0; for (int c = 0; c < nbCustomer; c++) { demand[c] = data.Next(); totalDemand += demand[c]; } int[] fixedCost = new int[nbLocation]; for (int l = 0; l < nbLocation; l++) { fixedCost[l] = data.Next(); } int[] capacity = new int[nbLocation]; for (int l = 0; l < nbLocation; l++) { capacity[l] = data.Next(); } CP cp = new CP(); IIntVar[] cust = new IIntVar[nbCustomer]; for (int c = 0; c < nbCustomer; c++) { cust[c] = cp.IntVar(0, nbLocation - 1); } IIntVar[] open = new IIntVar[nbLocation]; IIntVar[] load = new IIntVar[nbLocation]; for (int l = 0; l < nbLocation; l++) { open[l] = cp.IntVar(0, 1); load[l] = cp.IntVar(0, capacity[l]); } for (int l = 0; l < nbLocation; l++) { cp.Add(cp.Eq(open[l], cp.Gt(load[l], 0))); } cp.Add(cp.Pack(load, cust, demand)); IIntExpr obj = cp.Prod(open, fixedCost); for (int c = 0; c < nbCustomer; c++) { obj = cp.Sum(obj, cp.Element(cost[c], cust[c])); } cp.Add(cp.Minimize(obj)); cp.AddKPI(cp.Quot(totalDemand, cp.ScalProd(open, capacity)), "Mean occupancy"); INumExpr[] usage = new INumExpr[nbLocation]; for (int w = 0; w < nbLocation; w++) { usage[w] = cp.Sum(cp.Quot(load[w], capacity[w]), cp.Diff(1, open[w])); } cp.AddKPI(cp.Min(usage), "Min occupancy"); int[] custValues = { 19, 0, 11, 8, 29, 9, 29, 28, 17, 15, 7, 9, 18, 15, 1, 17, 25, 18, 17, 27, 22, 1, 26, 3, 22, 2, 20, 27, 2, 16, 1, 16, 12, 28, 19, 2, 20, 14, 13, 27, 3, 9, 18, 0, 13, 19, 27, 14, 12, 1, 15, 14, 17, 0, 7, 12, 11, 0, 25, 16, 22, 13, 16, 8, 18, 27, 19, 23, 26, 13, 11, 11, 19, 22, 28, 26, 23, 3, 18, 23, 26, 14, 29, 18, 9, 7, 12, 27, 8, 20 }; ISolution sol = cp.Solution(); for (int c = 0; c < nbCustomer; c++) { sol.SetValue(cust[c], custValues[c]); } cp.SetStartingPoint(sol); cp.SetParameter(CP.DoubleParam.TimeLimit, 10); cp.SetParameter(CP.IntParam.LogPeriod, 10000); cp.Solve(); }
public static void Main(string[] args) { CP cp = new CP(); int nbTruckConfigs = 7; // number of possible configurations for the truck int nbOrders = 21; int nbCustomers = 3; int nbTrucks = 15; //max number of travels of the truck int[] maxTruckConfigLoad = { //Capacity of the truck depends on its config 11, 11, 11, 11,10,10,10}; int maxLoad = Max(maxTruckConfigLoad) ; int[] customerOfOrder = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}; int[] volumes = { 3, 4, 3, 2, 5, 4, 11, 4, 5, 2, 4, 7, 3, 5, 2, 5, 6, 11, 1, 6, 3}; int[] colors = { 1, 2, 0, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2 ,0, 2, 1, 0, 2, 0, 0, 0}; int[] truckCost = { //cost for loading a truck of a given config 2, 2, 2, 3, 3, 3, 4}; //Decision variables IIntVar[] truckConfigs = cp.IntVarArray(nbTrucks,0,nbTruckConfigs-1); //configuration of the truck IIntVar[] where = cp.IntVarArray(nbOrders, 0, nbTrucks - 1); //In which truck is an order IIntVar[] load = cp.IntVarArray(nbTrucks, 0, maxLoad); //load of a truck IIntVar numUsed = cp.IntVar(0, nbTrucks); // number of trucks used IIntVar[] customerOfTruck = cp.IntVarArray(nbTrucks, 0, nbCustomers); // transition costs between trucks IIntTupleSet costTuples = cp.IntTable(3); cp.AddTuple(costTuples, new int[] {0,0,0}); cp.AddTuple(costTuples, new int[] {0,1,0}); cp.AddTuple(costTuples, new int[] {0,2,0}); cp.AddTuple(costTuples, new int[] {0,3,10}); cp.AddTuple(costTuples, new int[] {0,4,10}); cp.AddTuple(costTuples, new int[] {0,5,10}); cp.AddTuple(costTuples, new int[] {0,6,15}); cp.AddTuple(costTuples, new int[] {1,0,0}); cp.AddTuple(costTuples, new int[] {1,1,0}); cp.AddTuple(costTuples, new int[] {1,2,0}); cp.AddTuple(costTuples, new int[] {1,3,10}); cp.AddTuple(costTuples, new int[] {1,4,10}); cp.AddTuple(costTuples, new int[] {1,5,10}); cp.AddTuple(costTuples, new int[] {1,6,15}); cp.AddTuple(costTuples, new int[] {2,0,0}); cp.AddTuple(costTuples, new int[] {2,1,0}); cp.AddTuple(costTuples, new int[] {2,2,0}); cp.AddTuple(costTuples, new int[] {2,3,10}); cp.AddTuple(costTuples, new int[] {2,4,10}); cp.AddTuple(costTuples, new int[] {2,5,10}); cp.AddTuple(costTuples, new int[] {2,6,15}); cp.AddTuple(costTuples, new int[] {3,0,3}); cp.AddTuple(costTuples, new int[] {3,1,3}); cp.AddTuple(costTuples, new int[] {3,2,3}); cp.AddTuple(costTuples, new int[] {3,3,0}); cp.AddTuple(costTuples, new int[] {3,4,10}); cp.AddTuple(costTuples, new int[] {3,5,10}); cp.AddTuple(costTuples, new int[] {3,6,15}); cp.AddTuple(costTuples, new int[] {4,0,3}); cp.AddTuple(costTuples, new int[] {4,1,3}); cp.AddTuple(costTuples, new int[] {4,2,3}); cp.AddTuple(costTuples, new int[] {4,3,10}); cp.AddTuple(costTuples, new int[] {4,4,0}); cp.AddTuple(costTuples, new int[] {4,5,10}); cp.AddTuple(costTuples, new int[] {4,6,15}); cp.AddTuple(costTuples, new int[] {5,0,3}); cp.AddTuple(costTuples, new int[] {5,1,3}); cp.AddTuple(costTuples, new int[] {5,2,3}); cp.AddTuple(costTuples, new int[] {5,3,10}); cp.AddTuple(costTuples, new int[] {5,4,10}); cp.AddTuple(costTuples, new int[] {5,5,0}); cp.AddTuple(costTuples, new int[] {5,6,15}); cp.AddTuple(costTuples, new int[] {6,0,3}); cp.AddTuple(costTuples, new int[] {6,1,3}); cp.AddTuple(costTuples, new int[] {6,2,3}); cp.AddTuple(costTuples, new int[] {6,3,10}); cp.AddTuple(costTuples, new int[] {6,4,10}); cp.AddTuple(costTuples, new int[] {6,5,10}); cp.AddTuple(costTuples, new int[] {6,6,0}); IIntVar[] transitionCost = cp.IntVarArray(nbTrucks-1, 0, 1000); for (int i = 1; i < nbTrucks; i++) { IIntVar[] auxVars = new IIntVar[3]; auxVars[0]= truckConfigs[i-1]; auxVars[1]= truckConfigs[i]; auxVars[2]= transitionCost[i-1]; cp.Add(cp.AllowedAssignments(auxVars, costTuples)); } // constrain the volume of the orders in each truck cp.Add(cp.Pack(load, where, volumes, numUsed)); for (int i = 0; i < nbTrucks; i++) { cp.Add(cp.Le(load[i], cp.Element(maxTruckConfigLoad, truckConfigs[i]))); } // compatibility between the colors of an order and the configuration of its truck int[][] allowedContainerConfigs = new int[3][]; allowedContainerConfigs[0] = new int[] {0, 3, 4, 6}; allowedContainerConfigs[1] = new int[] {1, 3, 5, 6}; allowedContainerConfigs[2] = new int[] {2, 4, 5, 6}; for (int j = 0; j < nbOrders; j++) { IIntVar configOfContainer = cp.IntVar(allowedContainerConfigs[colors[j]]); cp.Add(cp.Eq(configOfContainer, cp.Element(truckConfigs,where[j]))); } // only one customer per truck for (int j = 0; j < nbOrders; j++) { cp.Add(cp.Eq( cp.Element(customerOfTruck,where[j]), customerOfOrder[j])); } // non used trucks are at the end for (int j = 1; j < nbTrucks; j++) { cp.Add(cp.Or( cp.Gt(load[j-1], 0) , cp.Eq(load[j], 0))); } // Dominance: the non used trucks keep the last used configuration cp.Add(cp.Gt(load[0],0)); for (int i = 1; i < nbTrucks; i++) { cp.Add(cp.Or(cp.Gt(load[i], 0), cp.Eq(truckConfigs[i], truckConfigs[i-1]))); } //Dominance: regroup deliveries with same configuration for (int i = nbTrucks-2; i >0; i--) { IConstraint Ct = cp.TrueConstraint(); for (int p = i+1; p < nbTrucks; p++) Ct = cp.And( cp.Neq(truckConfigs[p], truckConfigs[i-1]) , Ct); cp.Add( cp.Or(cp.Eq(truckConfigs[i], truckConfigs[i-1]), Ct)); } // Objective: first criterion for minimizing the cost for configuring and loading trucks // second criterion for minimizing the number of trucks IIntExpr obj1 = cp.Constant(0); for(int i = 0; i < nbTrucks; i++){ obj1 = cp.Sum(obj1, cp.Prod( cp.Element(truckCost,truckConfigs[i]),cp.Neq(load[i],0))); } obj1 = cp.Sum(obj1, cp.Sum(transitionCost)); IIntExpr obj2 = numUsed; // Search strategy: first assign order to truck ISearchPhase phase = cp.SearchPhase(where); // Multicriteria lexicographic optimization cp.Add(cp.Minimize(cp.StaticLex(obj1,obj2))); cp.SetParameter(CP.DoubleParam.TimeLimit, 20); cp.SetParameter(CP.IntParam.LogPeriod, 50000); cp.Solve(phase); double[] obj = cp.GetObjValues(); Console.WriteLine("Configuration cost: "+ (int)obj[0] + " Number of Trucks: " + (int)obj[1]); for(int i = 0; i < nbTrucks; i++) { if (cp.GetValue(load[i]) > 0) { Console.Write("Truck " + i + ": Config=" + cp.GetIntValue(truckConfigs[i]) + " Items= "); for (int j = 0; j < nbOrders; j++) { if (cp.GetValue(where[j]) == i) { Console.Write("<" + j + "," + colors[j] + "," + volumes[j] + "> "); } } Console.WriteLine(); } } }
static void Main(string[] args) { CP cp = new CP(); int weightSum=0; for (int o = 0; o < nbOrders; o++) weightSum += weight[o]; IIntVar[] where = new IIntVar[nbOrders]; for(int o = 0; o < nbOrders; o++) where[o] = cp.IntVar(0, nbSlabs-1); IIntVar[] load = new IIntVar[nbSlabs]; for(int m = 0; m < nbSlabs; m++) load[m] = cp.IntVar(0, weightSum); // Pack constraint cp.Add(cp.Pack(load, where, weight)); // Color constraints for(int m = 0; m < nbSlabs; m++) { IIntExpr[] colorExpArray = new IIntExpr[nbColors]; for(int c = 0; c < nbColors; c++) { IConstraint orCt = cp.FalseConstraint(); for(int o = 0; o < nbOrders; o++){ if (colors[o] == c){ orCt = cp.Or(orCt, cp.Eq(where[o], m)); } } colorExpArray[c] = cp.IntExpr(orCt); } cp.Add(cp.Le(cp.Sum(colorExpArray), 2)); } // Objective function int sizeLossValues = capacities[capacities.Length-1] - capacities[0] + 1; int[] lossValues = new int[sizeLossValues]; lossValues[0]= 0; int indexValue= 1; for(int q = 1; q < capacities.Length; q++){ for(int p = capacities[q-1] + 1; p <= capacities[q]; p++){ lossValues[indexValue] = capacities[q] - p; indexValue++; } } IIntExpr obj = cp.Constant(0); for(int m = 0; m < nbSlabs; m++){ obj = cp.Sum(obj, cp.Element(lossValues, load[m])); } cp.Add(cp.Minimize(obj)); // - A symmetry breaking constraint that is useful for small instances for(int m = 1; m < nbSlabs; m++){ cp.Add(cp.Ge(load[m-1],load[m])); } if (cp.Solve()){ Console.WriteLine("Optimal value: " + cp.GetValue(obj)); for (int m = 0; m < nbSlabs; m++) { int p = 0; for (int o = 0; o < nbOrders; o++) if (cp.GetValue(where[o]) == m) ++p; if (p == 0) continue; Console.Write("Slab " + m + " is used for order"); if (p > 1) Console.Write("s"); Console.Write(" :"); for (int o = 0; o < nbOrders; o++) { if (cp.GetValue(where[o]) == m) Console.Write(" " + o); } Console.WriteLine(); } } }
static void Main(string[] args) { CP cp = new CP(); coaching = new int[nbPersons]; int i; for (i = 0; i < nbPersons; i++) { coaching[i] = -1; } for (i = 0; i < 12; i = i + 2) // the 12 first of Service A are couples of coached/coach { coaching[i] = i + 1; coaching[i + 1] = i; } for (i = 20; i < 32; i = i + 2)// the 12 first of Service B are couples of coached/coach { coaching[i] = i + 1; coaching[i + 1] = i; } for (i = 40; i < nbPersons; i += 5) // the 4 first of Services C,D,E,F are couples of coached/coach { coaching[i] = i + 1; coaching[i + 1] = i; coaching[i + 2] = i + 3; coaching[i + 3] = i + 2; } //compute the possible solutions of a team IIntTupleSet tupleSet = MakeTeamTuples(cp); // groups[i] represents the ordered set of people in the team i IIntVar[][] groups = new IIntVar[nbTeams][]; for (i = 0; i < nbTeams; i++) { groups[i] = cp.IntVarArray(teamSize, 0, nbPersons - 1); cp.Add(cp.AllowedAssignments(groups[i], tupleSet)); } IIntVar[] allVars = cp.IntVarArray(nbPersons); int s = 0; int w; int p; for (w = 0; w < nbTeams; ++w) { for (p = 0; p < teamSize; ++p) { allVars[s] = groups[w][p]; ++s; } } cp.Add(cp.AllDiff(allVars)); // team[i] represents the number of the team of people number i IIntVar[] team = cp.IntVarArray(nbPersons, 0, nbTeams); for (w = 0; w < nbTeams; ++w) { for (p = 0; p < teamSize; ++p) { cp.Add(cp.Eq(cp.Element(team, groups[w][p]), w)); } } // Additional constraints // to improve efficiency we could force the following // first three constraints directly in MakeTeamTuples but the fourth // constraint cannot be expressed as a restriction of // the tuple set, since it is not local to a tuple cp.Add(cp.Or(cp.Eq(team[5], team[41]), cp.Eq(team[5], team[51]))); cp.Add(cp.Or(cp.Eq(team[15], team[40]), cp.Eq(team[15], team[51]))); cp.Add(cp.Or(cp.Eq(team[25], team[40]), cp.Eq(team[25], team[50]))); cp.Add(cp.Or(cp.Eq(team[20], team[24]), cp.Eq(team[22], team[50]))); //break symmetry: the teams are ordered according to the smallest in each team for (i = 0; i < nbTeams - 1; i++) { cp.Add(cp.Lt(groups[i][0], groups[i + 1][0])); } cp.SetParameter(CP.IntParam.AllDiffInferenceLevel, CP.ParameterValues.Extended); if (cp.Solve()) { Console.WriteLine(); Console.WriteLine("SOLUTION"); for (p = 0; p < nbTeams; ++p) { Console.Write("team " + p + " : "); for (w = 0; w < teamSize; ++w) { Console.Write((int)cp.GetValue(groups[p][w]) + " "); } Console.WriteLine(); } } else { Console.WriteLine("**** NO SOLUTION ****"); } }
public static void Main(string[] args) { int numPeriods = 6; if (args.Length > 0) numPeriods = Int32.Parse(args[0]); CP cp = new CP(); // // Variables // // Host boat choice IIntVar[] host = new IIntVar[numBoats]; for (int j = 0; j < numBoats; j++) { host[j] = cp.IntVar(0, 1, String.Format("H{0}", j)); } // Who is where each time period (time- and boat-based views) IIntVar[][] timePeriod = new IIntVar[numPeriods][]; for (int i = 0; i < numPeriods; i++) { timePeriod[i] = new IIntVar[numBoats]; for (int j = 0; j < numBoats; j++) { timePeriod[i][j] = cp.IntVar(0, numBoats-1, String.Format("T{0},{1}", i, j)); } } IIntVar[][] visits = Transpose(timePeriod); // // Objective // IIntVar numHosts = cp.IntVar(numPeriods, numBoats); cp.Add(cp.Eq(numHosts, cp.Sum(host))); cp.Add(cp.Minimize(numHosts)); // // Constraints // // Stay in my boat (host) or only visit other boats (guest) for (int i = 0; i < numBoats; i++) cp.Add(cp.Eq(cp.Count(visits[i], i), cp.Prod(host[i], numPeriods))); // Capacity constraints: only hosts have capacity for (int p = 0; p < numPeriods; p++) { IIntVar[] load = new IIntVar[numBoats]; for (int j = 0; j < numBoats; j++) { load[j] = cp.IntVar(0, boatSize[j], String.Format("L{0},{1}", p, j)); cp.Add(cp.Le(load[j], cp.Prod(host[j], boatSize[j]))); } cp.Add(cp.Pack(load, timePeriod[p], crewSize, numHosts)); } // No two crews meet more than once for (int i = 0; i < numBoats; i++) { for (int j = i + 1; j < numBoats; j++) { IIntExpr timesMet = cp.Constant(0); for (int p = 0; p < numPeriods; p++) timesMet = cp.Sum(timesMet, cp.Eq(visits[i][p], visits[j][p])); cp.Add(cp.Le(timesMet, 1)); } } // Host and guest boat constraints: given in problem spec cp.Add(cp.Eq(host[0], 1)); cp.Add(cp.Eq(host[1], 1)); cp.Add(cp.Eq(host[2], 1)); cp.Add(cp.Eq(host[39], 0)); cp.Add(cp.Eq(host[40], 0)); cp.Add(cp.Eq(host[41], 0)); // // Solving // if (cp.Solve()) { Console.WriteLine("Solution at cost = {0}", cp.GetValue(numHosts)); Console.Write("Hosts: "); for (int i = 0; i < numBoats; i++) Console.Write(cp.GetValue(host[i])); Console.WriteLine(); for (int p = 0; p < numPeriods; p++) { Console.WriteLine("Period {0}", p); for (int h = 0; h < numBoats; h++) { if (cp.GetValue(host[h]) > 0) { Console.Write("\tHost {0} : ", h); int load = 0; for (int i = 0; i < numBoats; i++) { if (cp.GetValue(visits[i][p]) == h) { load += crewSize[i]; Console.Write("{0} ({1}) ",i, crewSize[i]); } } Console.WriteLine(" --- {0} / {1}", load, boatSize[h]); } } } Console.WriteLine(); } }
static void Main(string[] args) { try { int n = 10; if (args.Length > 0) n = Int32.Parse(args[0]); if ((n % 2) == 1) n++; Console.WriteLine("Finding schedule for {0} teams", n); int nbWeeks = 2 * (n - 1); int nbGamesPerWeek = n / 2; int nbGames = n * (n - 1); CP cp = new CP(); IIntVar[][] games = new IIntVar[nbWeeks][]; IIntVar[][] home = new IIntVar[nbWeeks][]; IIntVar[][] away = new IIntVar[nbWeeks][]; for (int i = 0; i < nbWeeks; i++) { home[i] = cp.IntVarArray(nbGamesPerWeek, 0, n - 1); away[i] = cp.IntVarArray(nbGamesPerWeek, 0, n - 1); games[i] = cp.IntVarArray(nbGamesPerWeek, 0, nbGames - 1); } // // For each play slot, set up correspondance between game id, // home team, and away team // IIntTupleSet gha = cp.IntTable(3); int[] tuple = new int[3]; for (int i = 0; i < n; i++) { tuple[0] = i; for (int j = 0; j < n; j++) { if (i != j) { tuple[1] = j; tuple[2] = Game(i, j, n); cp.AddTuple(gha, tuple); } } } for (int i = 0; i < nbWeeks; i++) { for (int j = 0; j < nbGamesPerWeek; j++) { IIntVar[] vars = cp.IntVarArray(3); vars[0] = home[i][j]; vars[1] = away[i][j]; vars[2] = games[i][j]; cp.Add(cp.AllowedAssignments(vars, gha)); } } // // All teams play each week // for (int i = 0; i < nbWeeks; i++) { IIntVar[] teamsThisWeek = cp.IntVarArray(n); for (int j = 0; j < nbGamesPerWeek; j++) { teamsThisWeek[j] = home[i][j]; teamsThisWeek[nbGamesPerWeek + j] = away[i][j]; } cp.Add(cp.AllDiff(teamsThisWeek)); } // // Dual representation: for each game id, the play slot is maintained // IIntVar[] weekOfGame = cp.IntVarArray(nbGames, 0, nbWeeks - 1); IIntVar[] allGames = cp.IntVarArray(nbGames); IIntVar[] allSlots = cp.IntVarArray(nbGames, 0, nbGames - 1); for (int i = 0; i < nbWeeks; i++) for (int j = 0; j < nbGamesPerWeek; j++) allGames[i * nbGamesPerWeek + j] = games[i][j]; cp.Add(cp.Inverse(allGames, allSlots)); for (int i = 0; i < nbGames; i++) cp.Add(cp.Eq(weekOfGame[i], cp.Div(allSlots[i], nbGamesPerWeek))); // // Two half schedules. Cannot play the same pair twice in the same half. // Plus, impose a minimum number of weeks between two games involving // the same teams (up to six weeks) // int mid = nbWeeks / 2; int overlap = 0; if (n >= 6) overlap = min(n / 2, 6); for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int g1 = Game(i, j, n); int g2 = Game(j, i, n); cp.Add(cp.Equiv(cp.Ge(weekOfGame[g1], mid), cp.Lt(weekOfGame[g2], mid))); // Six week difference... if (overlap != 0) cp.Add(cp.Ge(cp.Abs(cp.Diff(weekOfGame[g1], weekOfGame[g2])), overlap)); } } // // Can't have three homes or three aways in a row. // IIntVar[][] playHome = new IIntVar[n][]; for (int i = 0; i < n; i++) { playHome[i] = cp.IntVarArray(nbWeeks, 0, 1); for (int j = 0; j < nbWeeks; j++) cp.Add(cp.Eq(playHome[i][j], cp.Count(home[j], i))); for (int j = 0; j < nbWeeks - 3; j++) { IIntVar[] window = cp.IntVarArray(3); for (int k = j; k < j + 3; k++) window[k - j] = playHome[i][k]; IIntExpr windowSum = cp.Sum(window); cp.Add(cp.Le(1, windowSum)); cp.Add(cp.Le(windowSum, 2)); } } // // If we start the season home, we finish away and vice versa. // for (int i = 0; i < n; i++) cp.Add(cp.Neq(playHome[i][0], playHome[i][nbWeeks - 1])); // // Objective: minimize the number of `breaks'. A break is // two consecutive home or away matches for a // particular team IIntVar[] teamBreaks = cp.IntVarArray(n, 0, nbWeeks / 2); for (int i = 0; i < n; i++) { IIntExpr nbreaks = cp.Constant(0); for (int j = 1; j < nbWeeks; j++) nbreaks = cp.Sum(nbreaks, cp.IntExpr(cp.Eq(playHome[i][j - 1], playHome[i][j]))); cp.Add(cp.Eq(teamBreaks[i], nbreaks)); } IIntVar breaks = cp.IntVar(n - 2, n * (nbWeeks / 2)); cp.Add(cp.Eq(breaks, cp.Sum(teamBreaks))); cp.Add(cp.Minimize(breaks)); // // Catalyzing constraints // // Each team plays home the same number of times as away for (int i = 0; i < n; i++) cp.Add(cp.Eq(cp.Sum(playHome[i]), nbWeeks / 2)); // Breaks must be even for each team for (int i = 0; i < n; i++) cp.Add(cp.Eq(cp.Modulo(teamBreaks[i], 2), 0)); // // Symmetry breaking constraints // // Teams are interchangeable. Fix first week. // Also breaks reflection symmetry of the whole schedule. for (int i = 0; i < nbGamesPerWeek; i++) { cp.Add(cp.Eq(home[0][i], i * 2)); cp.Add(cp.Eq(away[0][i], i * 2 + 1)); } // Order of games in each week is arbitrary. // Break symmetry by forcing an order. for (int i = 0; i < nbWeeks; i++) for (int j = 1; j < nbGamesPerWeek; j++) cp.Add(cp.Gt(games[i][j], games[i][j - 1])); cp.SetParameter(CP.DoubleParam.TimeLimit, 20); cp.SetParameter(CP.IntParam.LogPeriod, 10000); IVarSelector varSel = cp.SelectSmallest(cp.VarIndex(allGames)); ; IValueSelector valSel = cp.SelectRandomValue(); ISearchPhase phase = cp.SearchPhase(allGames, cp.IntVarChooser(varSel), cp.IntValueChooser(valSel)); cp.StartNewSearch(phase); while (cp.Next()) { Console.WriteLine("Solution at {0}", cp.GetValue(breaks)); } cp.EndSearch(); } catch (ILOG.Concert.Exception e) { Console.WriteLine("Error {0}", e); } }
public static void Main(string[] args) { try { string fileName = "../../../../examples/data/atsp.dat"; // Check the command line arguments if ( args.Length != 1 && args.Length != 2 ) { Usage(); return; } if ( ! (args[0].Equals("0") || args[0].Equals("1")) ) { Usage(); return; } bool sepFracSols = (args[0].ToCharArray()[0] == '0' ? false : true); if ( sepFracSols ) { System.Console.WriteLine("Benders' cuts separated to cut off: " + "Integer and fractional infeasible solutions."); } else { System.Console.WriteLine("Benders' cuts separated to cut off: " + "Only integer infeasible solutions."); } if ( args.Length == 2 ) fileName = args[1]; // Read arc_costs from data file (17 city problem) Data data = new Data(fileName); // create master ILP int numNodes = data.numNodes; Cplex cplex = new Cplex(); IIntVar[][] x = new IIntVar[numNodes][]; CreateMasterILP(cplex, data, x); // Create workerLP for Benders' cuts separation WorkerLP workerLP = new WorkerLP(numNodes); // Set up the cut callback to be used for separating Benders' cuts cplex.SetParam(Cplex.Param.Preprocessing.Presolve, false); // Set the maximum number of threads to 1. // This instruction is redundant: If MIP control callbacks are registered, // then by default CPLEX uses 1 (one) thread only. // Note that the current example may not work properly if more than 1 threads // are used, because the callback functions modify shared global data. // We refer the user to the documentation to see how to deal with multi-thread // runs in presence of MIP control callbacks. cplex.SetParam(Cplex.Param.Threads, 1); // Turn on traditional search for use with control callbacks cplex.SetParam(Cplex.Param.MIP.Strategy.Search, Cplex.MIPSearch.Traditional); cplex.Use(new BendersLazyConsCallback(x, workerLP)); if ( sepFracSols ) cplex.Use(new BendersUserCutCallback(x, workerLP)); // Solve the model and write out the solution if ( cplex.Solve() ) { System.Console.WriteLine(); System.Console.WriteLine("Solution status: " + cplex.GetStatus()); System.Console.WriteLine("Objective value: " + cplex.ObjValue); if ( cplex.GetStatus().Equals(Cplex.Status.Optimal) ) { // Write out the optimal tour int i, j; double[][] sol = new double[numNodes][]; int[] succ = new int[numNodes]; for (j = 0; j < numNodes; ++j) succ[j] = -1; for (i = 0; i < numNodes; ++i) { sol[i] = cplex.GetValues(x[i]); for (j = 0; j < numNodes; ++j) { if ( sol[i][j] > 1e-03 ) succ[i] = j; } } System.Console.WriteLine("Optimal tour:"); i = 0; while ( succ[i] != 0 ) { System.Console.Write(i + ", "); i = succ[i]; } System.Console.WriteLine(i); } else { System.Console.WriteLine("Solution status is not Optimal"); } } else { System.Console.WriteLine("No solution available"); } workerLP.End(); cplex.End(); } catch (ILOG.Concert.Exception ex) { System.Console.WriteLine("Concert Error: " + ex); } catch (InputDataReader.InputDataReaderException ex) { System.Console.WriteLine("Data Error: " + ex); } catch (System.IO.IOException ex) { System.Console.WriteLine("IO Error: " + ex); } }
static void Main() { try { string resultFilename = "./ResultFiles/MTSP_MTZ.csv"; string filename = "./DataFiles/Data.dat"; Data data = new Data(filename); double timeFactor = 0; double distanceFactor = 1; double step = 0.1; int routeCounter = 0; File.WriteAllText(resultFilename, ""); do { using (Cplex cplex = new Cplex()) { #region [Decision Variables] IIntVar[][] x = new IIntVar[data.n][]; IIntVar Q = cplex.IntVar(1, 250, "Q"); for (int i = 0; i < data.n; i++) { x[i] = cplex.BoolVarArray(data.n); cplex.Add(x[i]); } #endregion #region [Objective Function] INumExpr obj = cplex.NumExpr(); for (int i = 0; i < data.n; i++) { for (int j = 0; j < data.n; j++) { if (i != j) { obj = cplex.Sum(obj, cplex.Prod( ( (timeFactor * data.timeNormalized[i][j]) + (distanceFactor * data.distanceNormalized[i][j]) ), x[i][j])); } } } cplex.AddMinimize(obj); #endregion #region [Restrictions] for (int j = 0; j < data.n; j++) { ILinearNumExpr sumj = cplex.LinearNumExpr(); for (int i = 0; i < data.n; i++) { if (i != j) { sumj.AddTerm(1, x[i][j]); } } cplex.AddEq(sumj, 1); } for (int i = 0; i < data.n; i++) { ILinearNumExpr sumi = cplex.LinearNumExpr(); for (int j = 0; j < data.n; j++) { if (i != j) { sumi.AddTerm(1, x[i][j]); } } cplex.AddEq(sumi, 1); } #endregion cplex.SetParam(Cplex.DoubleParam.WorkMem, 4000.0); cplex.SetParam(Cplex.Param.MIP.Strategy.File, 2); cplex.SetParam(Cplex.DoubleParam.EpGap, 0.1); cplex.SetParam(Cplex.BooleanParam.MemoryEmphasis, true); cplex.SetParam(Cplex.IntParam.VarSel, 4); SOLVE: Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); if (cplex.Solve()) { stopWatch.Stop(); double[][] sol_x = new double[data.n][]; for (int i = 0; i < data.n; i++) { sol_x[i] = cplex.GetValues(x[i]); } int[] tour = FindSubTour(sol_x); if (tour.Length < data.n) { ILinearNumExpr sumx = cplex.LinearNumExpr(); for (int i = 0; i < tour.Length; i++) { for (int j = 0; j < tour.Length; j++) { sumx.AddTerm(1, x[tour[i]][tour[j]]); } } cplex.AddLazyConstraint(cplex.AddLe(cplex.Diff(sumx, tour.Length), -1)); goto SOLVE; } double timeTotal = 0; double distanceTotal = 0; for (int i = 0; i < data.n; i++) { for (int j = 0; j < data.n; j++) { timeTotal += data.time[i][j] * sol_x[i][j]; distanceTotal += data.distance[i][j] * sol_x[i][j]; } } StreamWriter file = new StreamWriter(resultFilename, true); file.WriteLine($"{timeFactor},{distanceFactor},{stopWatch.Elapsed.TotalSeconds},{cplex.ObjValue},{timeTotal},{distanceTotal}"); file.Close(); StreamWriter fileRouteResult = new StreamWriter($"./ResultFiles/Route-{routeCounter}.txt"); for (int i = 0; i < data.n; i++) { for (int j = 0; j < data.n; j++) { if (sol_x[i][j] == 1) { fileRouteResult.WriteLine($"From city {i} to city {j}"); } } } fileRouteResult.Close(); } cplex.End(); } timeFactor += step; distanceFactor -= step; routeCounter++; } while (timeFactor <= 1); } catch (ILOG.Concert.Exception ex) { StreamWriter errorfile = new StreamWriter("./ErrorLog.txt"); errorfile.WriteLine("Exception Kind: ILOG.Concert.Exception (Concert Error)"); errorfile.WriteLine("Message: " + ex.Message); errorfile.WriteLine("StackTrace: " + ex.StackTrace); errorfile.Close(); } catch (InputDataReader.InputDataReaderException ex) { StreamWriter errorfile = new StreamWriter("./ErrorLog.txt"); errorfile.WriteLine("Exception Kind: InputDataReader.InputDataReaderException (Data Error)"); errorfile.WriteLine("Message: " + ex.Message); errorfile.WriteLine("StackTrace: " + ex.StackTrace); errorfile.Close(); } catch (System.IO.IOException ex) { StreamWriter errorfile = new StreamWriter("./ErrorLog.txt"); errorfile.WriteLine("Exception Kind: System.IO.IOException (IO Error)"); errorfile.WriteLine("Message: " + ex.Message); errorfile.WriteLine("StackTrace: " + ex.StackTrace); errorfile.Close(); } }
static void Main(string[] args) { String filename; if (args.Length > 0) filename = args[0]; else filename = "../../../../examples/data/plant_location.data"; DataReader data = new DataReader(filename); int nbCustomer = data.Next(); int nbLocation = data.Next(); int[][] cost = new int[nbCustomer][]; for (int c = 0; c < nbCustomer; c++) { cost[c] = new int[nbLocation]; for (int l = 0; l < nbLocation; l++) cost[c][l] = data.Next(); } int[] demand = new int[nbCustomer]; for (int c = 0; c < nbCustomer; c++) { demand[c] = data.Next(); } int[] fixedCost = new int[nbLocation]; for (int l = 0; l < nbLocation; l++) { fixedCost[l] = data.Next(); } int[] capacity = new int[nbLocation]; for (int l = 0; l < nbLocation; l++) { capacity[l] = data.Next(); } CP cp = new CP(); IIntVar[] cust = new IIntVar[nbCustomer]; for (int c = 0; c < nbCustomer; c++) { cust[c] = cp.IntVar(0, nbLocation - 1); } IIntVar[] open = new IIntVar[nbLocation]; IIntVar[] load = new IIntVar[nbLocation]; for (int l = 0; l < nbLocation; l++) { open[l] = cp.IntVar(0, 1); load[l] = cp.IntVar(0, capacity[l]); } for (int l = 0; l < nbLocation; l++) { cp.Add(cp.Eq(open[l], cp.Gt(load[l], 0))); } cp.Add(cp.Pack(load, cust, demand)); IIntExpr obj = cp.Prod(open, fixedCost); for (int c = 0; c < nbCustomer; c++) { obj = cp.Sum(obj, cp.Element(cost[c], cust[c])); } cp.Add(cp.Minimize(obj)); int[] custValues = { 19, 0, 11, 8, 29, 9, 29, 28, 17, 15, 7, 9, 18, 15, 1, 17, 25, 18, 17, 27, 22, 1, 26, 3, 22, 2, 20, 27, 2, 16, 1, 16, 12, 28, 19, 2, 20, 14, 13, 27, 3, 9, 18, 0, 13, 19, 27, 14, 12, 1, 15, 14, 17, 0, 7, 12, 11, 0, 25, 16, 22, 13, 16, 8, 18, 27, 19, 23, 26, 13, 11, 11, 19, 22, 28, 26, 23, 3, 18, 23, 26, 14, 29, 18, 9, 7, 12, 27, 8, 20 }; ISolution sol = cp.Solution(); for (int c = 0; c < nbCustomer; c++) sol.SetValue(cust[c], custValues[c]); cp.SetStartingPoint(sol); cp.SetParameter(CP.DoubleParam.TimeLimit, 10); cp.SetParameter(CP.IntParam.LogPeriod, 10000); cp.Solve(); }
static void Main(string[] args) { int D = 5; int W = 5; int H = 3; int G = 2; int T = 12; int[] k_g = new int[] { 2, 2 }; int ALLK = 4; int[] cc_d = new int[] { 2, 1, 2, 1, 2 }; int[] ave = new int[] { 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1 }; int[] dur = new int[] { 1, 2, 1, 1, 2 }; int[] prf_D = new int[] { 2, 1, 1, 1, 100 }; int[] indexg_d = new int[] { 0, 1, 1, 1, 0 }; CP roster = new CP(); // intern availbility INumToNumStepFunction resource_AveIntern = roster.NumToNumStepFunction(0, T, 100, "AvailibilityOfIntern"); for (int t = 0; t < T; t++) { if (ave[t] == 0) { resource_AveIntern.SetValue(t, t + 1, 0); } } // discipline IIntervalVar[] discipline_d = new IIntervalVar[D]; ICumulFunctionExpr hospitalNotRR = roster.CumulFunctionExpr(); for (int d = 0; d < D; d++) { discipline_d[d] = roster.IntervalVar(); discipline_d[d].EndMax = T; discipline_d[d].EndMin = dur[d]; discipline_d[d].LengthMax = dur[d]; discipline_d[d].LengthMin = dur[d]; discipline_d[d].SizeMax = dur[d]; discipline_d[d].SizeMin = dur[d]; discipline_d[d].StartMax = T; discipline_d[d].StartMin = 0; discipline_d[d].SetIntensity(resource_AveIntern, 100); hospitalNotRR.Add(roster.Pulse(discipline_d[d], 1)); discipline_d[d].SetOptional(); } IIntervalSequenceVar dis = roster.IntervalSequenceVar(discipline_d); roster.Add(roster.Ge(roster.PresenceOf(discipline_d[1]), roster.PresenceOf(discipline_d[4]))); roster.Add(roster.Before(dis, discipline_d[1], discipline_d[4])); roster.Add(roster.NoOverlap(discipline_d)); // desciplien for not renewable resources IIntVar[] height_t = new IIntVar[T]; for (int t = 0; t < T; t++) { height_t[t] = roster.IntVar(0, 1); } INumToNumSegmentFunction piecewise = roster.NumToNumSegmentFunction(new double[] { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11 }, new double[] { 10, 0, 10, 1, 10, 2, 10, 3, 10, 4, 10, 5, 10, 6, 10, 7, 10, 8, 10, 9, 10, 10, 10, 11 }); INumExpr rc = roster.NumExpr(); for (int d = 0; d < D; d++) { rc = roster.Sum(rc, roster.StartEval(discipline_d[d], piecewise, 0)); } for (int t = 0; t < T; t++) { } IIntervalVar[] disciplineNR_d = new IIntervalVar[D]; for (int d = 0; d < D; d++) { disciplineNR_d[d] = roster.IntervalVar(); disciplineNR_d[d].EndMax = T; disciplineNR_d[d].EndMin = T; disciplineNR_d[d].LengthMax = T; disciplineNR_d[d].LengthMin = T; disciplineNR_d[d].SizeMax = T; disciplineNR_d[d].SizeMin = T; disciplineNR_d[d].StartMax = T; disciplineNR_d[d].StartMin = 0; disciplineNR_d[d].SetOptional(); roster.IfThen(roster.PresenceOf(discipline_d[d]), roster.PresenceOf(disciplineNR_d[d])); } //roster.Add(roster.IfThen(roster.PresenceOf(discipline_d[4]), roster.And(roster.Le(roster.EndOf(discipline_d[4]), roster.StartOf(discipline_d[0])),roster.PresenceOf(discipline_d[0])))); //roster.Add(roster.StartBeforeEnd(discipline_d[4],discipline_d[0])); // hospital changes //ICumulFunctionExpr[] hospital //for (int d = 0; d < D; d++) //{ // roster.IfThen(roster.PresenceOf(disciplineNR_d[d]),); //} // hospital assignment IIntervalVar[][] Hospital_dh = new IIntervalVar[D][]; for (int d = 0; d < D; d++) { Hospital_dh[d] = new IIntervalVar[H]; for (int h = 0; h < H; h++) { Hospital_dh[d][h] = roster.IntervalVar(); Hospital_dh[d][h].EndMax = T; Hospital_dh[d][h].EndMin = dur[d]; Hospital_dh[d][h].LengthMax = dur[d]; Hospital_dh[d][h].LengthMin = dur[d]; Hospital_dh[d][h].SizeMax = dur[d]; Hospital_dh[d][h].SizeMin = dur[d]; Hospital_dh[d][h].StartMax = T; Hospital_dh[d][h].StartMin = 0; Hospital_dh[d][h].SetOptional(); if (h == 0 && (d != 4)) { Hospital_dh[d][h].SetAbsent(); } if (h == 1 && (d == 4)) { Hospital_dh[d][h].SetAbsent(); } if (h == 2 && (d == 4)) { Hospital_dh[d][h].SetAbsent(); } } roster.Add(roster.Alternative(discipline_d[d], Hospital_dh[d])); } IIntervalVar[] disHospSetUp_dh = new IIntervalVar[D * H]; int[] type = new int[D * H]; for (int dh = 0; dh < D * H; dh++) { int dIndex = dh % D; int hIndex = dh / D; disHospSetUp_dh[dh] = roster.IntervalVar("DsiHosp" + "[" + dIndex + "][" + hIndex + "]"); type[dh] = hIndex; disHospSetUp_dh[dh].SetOptional(); disHospSetUp_dh[dh] = Hospital_dh[dIndex][hIndex]; } // changes IIntervalSequenceVar cc = roster.IntervalSequenceVar(disHospSetUp_dh, type); roster.NoOverlap(cc); IIntVar[][] change_dD = new IIntVar[D][]; for (int d = 0; d < D; d++) { change_dD[d] = new IIntVar[D]; for (int dd = 0; dd < D; dd++) { change_dD[d][dd] = roster.IntVar(0, 1, "change_dD[" + d + "][" + dd + "]"); } } IIntVar[] change_d = new IIntVar[D]; for (int d = 0; d < D; d++) { change_d[d] = roster.IntVar(0, 1, "change_d[" + d + "]"); } for (int dh = 0; dh < D * H; dh++) { int dIndex = dh % D; int hIndex = dh / D; IIntExpr chngD = roster.IntExpr(); chngD = roster.Sum(chngD, change_d[dIndex]); roster.Add(roster.IfThen(roster.And(roster.PresenceOf(disHospSetUp_dh[dh]), roster.Neq(roster.TypeOfNext(cc, disHospSetUp_dh[dh], hIndex, hIndex), hIndex)), roster.Eq(chngD, 1))); for (int ddh = 0; ddh < D * H; ddh++) { int ddIndex = ddh % D; int hhIndex = ddh / D; if (hhIndex == hIndex || dIndex == ddIndex) { continue; } } } //IIntVar[][] y_dD = new IIntVar[D][]; //for (int d = 0; d < D; d++) //{ // y_dD[d] = new IIntVar[D]; // for (int dd= 0; dd < D; dd++) // { // y_dD[d][dd] = roster.IntVar(0,1); // if (d == dd) // { // y_dD[d][dd] = roster.IntVar(0, 0); // } // } //} //for (int d = 0; d < D; d++) //{ // for (int dd = 0; dd < D; dd++) // { // if (d != dd) // { // for (int h = 0; h < H; h++) // { // for (int hh = 0; hh < H; hh++) // { // if (d != dd && h != hh && true) // { // IIntExpr yyy = roster.IntExpr(); // yyy = roster.Sum(yyy,roster.Prod(T,y_dD[d][dd])); // yyy = roster.Sum(yyy, roster.Prod(1, roster.EndOf(Hospital_dh[dd][hh]))); // yyy = roster.Sum(yyy, roster.Prod(-1, roster.StartOf(Hospital_dh[d][h]))); // roster.Add( roster.IfThen(roster.And(roster.PresenceOf(Hospital_dh[d][h]), roster.PresenceOf(Hospital_dh[dd][hh])), roster.AddGe(yyy, 0))); // } // } // } // } // } //} //for (int d = 0; d < D; d++) //{ // for (int dd = 0; dd < D; dd++) // { // if (d == dd) // { // continue; // } // IIntExpr change = roster.IntExpr(); // change = roster.Sum(change, change_dD[dd][d]); // change = roster.Sum(change, roster.Prod(-1, y_dD[dd][d])); // for (int ddd = 0; ddd < D; ddd++) // { // if (ddd == d || ddd == dd) // { // continue; // } // change = roster.Sum(change, change_dD[dd][ddd]); // } // roster.Add(roster.IfThen(roster.And(roster.PresenceOf(discipline_d[d]), roster.PresenceOf(discipline_d[dd])), roster.AddEq(change, 0))); // } //} // all group assignment IIntExpr allPossibleCourses = roster.IntExpr(); for (int d = 0; d < D; d++) { allPossibleCourses = roster.Sum(allPossibleCourses, roster.Prod(cc_d[d], roster.PresenceOf(discipline_d[d]))); } roster.AddEq(allPossibleCourses, ALLK); // group assignment for (int g = 0; g < G; g++) { IIntExpr groupedCours_g = roster.IntExpr(); for (int d = 0; d < D; d++) { if (indexg_d[d] == g) { groupedCours_g = roster.Sum(groupedCours_g, roster.Prod(cc_d[d], roster.PresenceOf(discipline_d[d]))); } } roster.AddGe(groupedCours_g, k_g[g]); } // stay in one hospital // objective function INumExpr objExp = roster.NumExpr(); // discipline desire for (int d = 0; d < D; d++) { objExp = roster.Sum(objExp, roster.Prod(prf_D[d], roster.PresenceOf(discipline_d[d]))); for (int dd = 0; dd < D; dd++) { objExp = roster.Sum(objExp, roster.Prod(-1, change_d[d])); } } objExp = roster.Sum(objExp, rc); IIntExpr makespan = roster.IntExpr(); for (int d = 0; d < D; d++) { makespan = roster.Max(makespan, roster.EndOf(discipline_d[d])); } IIntVar wait = roster.IntVar(0, T); IIntExpr waitConst = roster.IntExpr(); waitConst = roster.Sum(waitConst, wait); waitConst = roster.Sum(waitConst, roster.Prod(-1, makespan)); for (int d = 0; d < D; d++) { waitConst = roster.Sum(waitConst, roster.Prod(dur[d], roster.PresenceOf(discipline_d[d]))); } roster.AddEq(waitConst, 0); roster.AddMaximize(objExp); roster.ExportModel("Roster.cpo"); roster.SetParameter(CP.IntParam.TimeMode, CP.ParameterValues.ElapsedTime); roster.SetParameter(CP.IntParam.LogVerbosity, CP.ParameterValues.Quiet); roster.SetParameter(CP.IntParam.SolutionLimit, 10); // solve it now if (roster.Solve()) { Console.WriteLine("this is the cost of the CP column {0}", roster.ObjValue); for (int d = 0; d < D; d++) { if (roster.IsPresent(discipline_d[d])) { Console.WriteLine("Discipline {0} with CC {1} and Dur {2} and Prf {3} started at time {4} and finished at time {5}", d, cc_d[d], dur[d], prf_D[d], roster.GetStart(discipline_d[d]), roster.GetEnd(discipline_d[d])); } } for (int d = 0; d < D; d++) { for (int h = 0; h < H; h++) { if (roster.IsPresent(Hospital_dh[d][h])) { Console.WriteLine("Discipline {0} with CC {1} and Dur {2} and Prf {3} started at time {4} and finished at time {5} at Hospitail {6}", d, cc_d[d], dur[d], prf_D[d], roster.GetStart(Hospital_dh[d][h]), roster.GetEnd(Hospital_dh[d][h]), h); } } } for (int d = 0; d < D * H; d++) { int dIndex = d % D; int hIndex = d / D; if (roster.IsPresent(disHospSetUp_dh[d])) { Console.WriteLine("discpline " + dIndex + " in hospital " + hIndex); } } for (int d = 0; d < D; d++) { if (roster.GetValue(change_d[d]) > 0.5) { Console.WriteLine("We have change for discipline {0}", d); } for (int dd = 0; dd < D; dd++) { if (d == dd) { continue; } } } Console.WriteLine("========================================="); Console.WriteLine("Wainting time {0}", roster.GetValue(wait)); } }
/// <summary> /// return a list of words that can be played, left over letters are the last word /// </summary> /// <param name="chips">All of the chips to conisder, first ones are on the board</param> /// <param name="numberOnBoard">The number of leading chips are on the board already</param> /// <returns></returns> public static List <Chip[]> Solve(List <Chip> chips, int numberOnBoard, bool suppress = true) { if (chips == null || chips.Count == 0) { Utility.Warning("Chips is null or empty!"); return(null); } int chip_count = chips.Count; int word_count = chip_count / 3 + 1; Cplex model = new Cplex(); IIntVar[] X = model.BoolVarArray(chip_count); // should we place the ith chip IIntVar[][] Y = new IIntVar[chip_count][]; // which word do we place the ith chip on IIntVar[] WO = model.BoolVarArray(word_count); // flag for if the jth word is an order word or not IIntVar[] WC = model.BoolVarArray(word_count); // flag for if the jth word is a color word or not IIntVar[] WN = model.BoolVarArray(word_count); // flag for if the jth word is not used or is used IIntVar[][] UO = new IIntVar[word_count][]; // what is the number associated with this word (used only if a color word) IIntVar[][] UC = new IIntVar[word_count][]; // what is the color associated with this word (used only if a order word) IIntVar[][] PC = new IIntVar[word_count][]; // if i maps to word j and j is a color word, this will be 1 at [j][i] IIntVar[][] PO = new IIntVar[word_count][]; // if i maps to word j and j is a order word, this will be 1 at [j][i] (if and only if) // Initialize for (int i = 0; i < chip_count; i++) { Y[i] = model.BoolVarArray(word_count); } for (int i = 0; i < word_count; i++) { UC[i] = model.BoolVarArray(Chip.COLORCOUNT); } for (int i = 0; i < word_count; i++) { UO[i] = model.BoolVarArray(Chip.NUMBERCOUNT); } for (int i = 0; i < word_count; i++) { PC[i] = model.BoolVarArray(chip_count); } for (int i = 0; i < word_count; i++) { PO[i] = model.BoolVarArray(chip_count); } // for each word which chips map to it IIntVar[][] Yt = new IIntVar[word_count][]; for (int i = 0; i < word_count; i++) { Yt[i] = new IIntVar[chip_count]; for (int j = 0; j < chip_count; j++) { Yt[i][j] = Y[j][i]; } } // maximize the number of placed chips model.AddMaximize(model.Sum(X)); // if we place i, we need to map it to some word for (int i = 0; i < chip_count; i++) { model.AddLe(X[i], model.Sum(Y[i])); } // we can map to at most 1 value for (int i = 0; i < chip_count; i++) { model.AddLe(model.Sum(Y[i]), 1); } // if any chip maps to word j, turn the not used flag off for (int j = 0; j < word_count; j++) { for (int i = 0; i < chip_count; i++) { model.AddLe(Y[i][j], model.Diff(1, WN[j])); } } // if a word is used, make sure it has at least 3 chips for (int j = 0; j < word_count; j++) { model.AddLe(model.Prod(3, model.Diff(1, WN[j])), model.Sum(Yt[j])); } // first 'numberOnBoard' chips are on the board and thus must be placed for (int i = 0; i < numberOnBoard; i++) { model.AddEq(X[i], 1); } // each word is either an order word or a color word for (int i = 0; i < word_count; i++) { model.AddEq(model.Sum(WO[i], WC[i], WN[i]), 1); } // if i maps to word j and j is a color word make sure PC[j][i] is 1 for (int j = 0; j < word_count; j++) { for (int i = 0; i < chip_count; i++) { model.AddGe(model.Sum(1, PC[j][i]), model.Sum(WC[j], Y[i][j])); } } // if i maps to word j and j is a order word, PO will be 1 at [j][i] (if and only if) for (int j = 0; j < word_count; j++) { for (int i = 0; i < chip_count; i++) { model.AddGe(model.Sum(1, PO[j][i]), model.Sum(WO[j], Y[i][j])); model.AddLe(PO[j][i], WO[j]); model.AddLe(PO[j][i], Y[i][j]); } } // ************************************************ // ************ TYPE CONSTRAINTS ****************** // ************************************************ for (int i = 0; i < chip_count; i++) { for (int j = 0; j < word_count; j++) { // if this is a color word and a chip maps to it then the numbers of each chip on this word must match for (int k = 0; k < Chip.NUMBERCOUNT; k++) { var bnd = model.Sum(WO[j], model.Diff(1, Y[i][j])); model.AddLe(model.Diff(UO[j][k], chips[i].number[k] ? 1 : 0), bnd); model.AddLe(model.Diff(chips[i].number[k] ? 1 : 0, UO[j][k]), bnd); } // if this is a order word and a chip maps to it then the colors of each chip on this word must match for (int k = 0; k < Chip.COLORCOUNT; k++) { var bnd = model.Sum(WC[j], model.Diff(1, Y[i][j])); model.AddLe(model.Diff(UC[j][k], chips[i].color[k] ? 1 : 0), bnd); model.AddLe(model.Diff(chips[i].color[k] ? 1 : 0, UC[j][k]), bnd); } } } // if this is a color word, ensure that at most one of each color is allowed for (int j = 0; j < word_count; j++) { for (int k = 0; k < Chip.COLORCOUNT; k++) { int[] colstack = new int[chip_count]; for (int i = 0; i < chip_count; i++) { colstack[i] = chips[i].color[k] ? 1 : 0; } model.Add(model.IfThen(model.Eq(WC[j], 1), model.Le(model.ScalProd(colstack, PC[j]), 1))); } } // ensure that the numbers in an order word are sequential for (int j = 0; j < word_count; j++) { IIntVar[] V = model.BoolVarArray(Chip.NUMBERCOUNT); for (int k = 0; k < Chip.NUMBERCOUNT; k++) { int[] numstack = new int[chip_count]; for (int i = 0; i < chip_count; i++) { numstack[i] = chips[i].number[k] ? 1 : 0; } // if this is an order word put the binary numbers into a vector of flags for those numbers model.Add(model.IfThen(model.Eq(WO[j], 1), model.Eq(model.ScalProd(numstack, PO[j]), V[k]))); } // for each number either the next flag is strictly larger, meaning the start of the sequence // or every flag after a decrease is 0, the end of a sequence for (int i = 0; i < Chip.NUMBERCOUNT - 1; i++) { IIntVar Z = model.BoolVar(); model.AddLe(model.Diff(V[i], V[i + 1]), Z); for (int k = i + 1; k < Chip.NUMBERCOUNT; k++) { model.AddLe(V[k], model.Diff(1, Z)); } } } List <Chip[]> words = new List <Chip[]>(); if (suppress) { model.SetOut(null); } Utility.Log("Thinking..."); if (model.Solve()) { for (int j = 0; j < word_count; j++) { if (model.GetValue(WN[j]) > 0.5) { continue; } List <Chip> word = new List <Chip>(); double[] flags = model.GetValues(Yt[j]); for (int i = 0; i < chip_count; i++) { if (flags[i] > 0.5) { word.Add(chips[i]); } } // if this is a color word else it is an order word if (model.GetValue(WC[j]) > 0.5) { words.Add(word.OrderBy(p => Array.IndexOf(p.color, true)).ToArray()); } else { words.Add(word.OrderBy(p => Array.IndexOf(p.number, true)).ToArray()); } } } else { Utility.Warning("No possible moves found!"); } model.Dispose(); Chip[] notplayed = chips.Where(p => !words.Any(q => q.Contains(p))).ToArray(); words.Add(notplayed); return(words); }
static public void Main(string[] args) { int numPeriods = 6; if (args.Length > 0) { numPeriods = Int32.Parse(args[0]); } CP cp = new CP(); // // Variables // // Host boat choice IIntVar[] host = new IIntVar[numBoats]; for (int j = 0; j < numBoats; j++) { host[j] = cp.IntVar(0, 1, String.Format("H{0}", j)); } // Who is where each time period (time- and boat-based views) IIntVar[][] timePeriod = new IIntVar[numPeriods][]; for (int i = 0; i < numPeriods; i++) { timePeriod[i] = new IIntVar[numBoats]; for (int j = 0; j < numBoats; j++) { timePeriod[i][j] = cp.IntVar(0, numBoats - 1, String.Format("T{0},{1}", i, j)); } } IIntVar[][] visits = Transpose(timePeriod); // // Objective // IIntVar numHosts = cp.IntVar(numPeriods, numBoats); cp.Add(cp.Eq(numHosts, cp.Sum(host))); cp.Add(cp.Minimize(numHosts)); // // Constraints // // Stay in my boat (host) or only visit other boats (guest) for (int i = 0; i < numBoats; i++) { cp.Add(cp.Eq(cp.Count(visits[i], i), cp.Prod(host[i], numPeriods))); } // Capacity constraints: only hosts have capacity for (int p = 0; p < numPeriods; p++) { IIntVar[] load = new IIntVar[numBoats]; for (int j = 0; j < numBoats; j++) { load[j] = cp.IntVar(0, boatSize[j], String.Format("L{0},{1}", p, j)); cp.Add(cp.Le(load[j], cp.Prod(host[j], boatSize[j]))); } cp.Add(cp.Pack(load, timePeriod[p], crewSize, numHosts)); } // No two crews meet more than once for (int i = 0; i < numBoats; i++) { for (int j = i + 1; j < numBoats; j++) { IIntExpr timesMet = cp.Constant(0); for (int p = 0; p < numPeriods; p++) { timesMet = cp.Sum(timesMet, cp.Eq(visits[i][p], visits[j][p])); } cp.Add(cp.Le(timesMet, 1)); } } // Host and guest boat constraints: given in problem spec cp.Add(cp.Eq(host[0], 1)); cp.Add(cp.Eq(host[1], 1)); cp.Add(cp.Eq(host[2], 1)); cp.Add(cp.Eq(host[39], 0)); cp.Add(cp.Eq(host[40], 0)); cp.Add(cp.Eq(host[41], 0)); // // Solving // if (cp.Solve()) { Console.WriteLine("Solution at cost = {0}", cp.GetValue(numHosts)); Console.Write("Hosts: "); for (int i = 0; i < numBoats; i++) { Console.Write(cp.GetValue(host[i])); } Console.WriteLine(); for (int p = 0; p < numPeriods; p++) { Console.WriteLine("Period {0}", p); for (int h = 0; h < numBoats; h++) { if (cp.GetValue(host[h]) > 0) { Console.Write("\tHost {0} : ", h); int load = 0; for (int i = 0; i < numBoats; i++) { if (cp.GetValue(visits[i][p]) == h) { load += crewSize[i]; Console.Write("{0} ({1}) ", i, crewSize[i]); } } Console.WriteLine(" --- {0} / {1}", load, boatSize[h]); } } } Console.WriteLine(); } }
private void runModel(List <Employee> employees, List <Shift> shifts) { StreamWriter writer = File.CreateText(@"C:\Users\user\Desktop\cplex log\result9.txt"); try { Cplex model = new Cplex(); model.SetOut(writer); //------------------------------ //---Variable initialization----- //------------------------------ //Assignment variables IDictionary <string, IIntVar> assignVars = new Dictionary <string, IIntVar>(); employees.ForEach(employee => { shifts.ForEach(shift => { string name = getAssignVarName(employee, shift); assignVars.Add(name, model.BoolVar(name)); }); }); //Total assignment hours INumVar totalAssignHourVar = model.NumVar(0, Double.MaxValue, getTotalAssignVarName()); //---------------------------------- //---Constraints initialization----- //----------------------------------- //1) Min rest constraint //2) Goal total assigned hours constraint ILinearNumExpr sumAssignHourExpr = model.LinearNumExpr(); sumAssignHourExpr.AddTerm(-1.0, totalAssignHourVar); employees.ForEach(employee => { shifts.ForEach(shift1 => { ILinearNumExpr sumOverlapExpr = model.LinearNumExpr(); string name1 = getAssignVarName(employee, shift1); IIntVar assignVar1 = assignVars[name1]; sumOverlapExpr.AddTerm(1.0, assignVar1); shifts.ForEach(shift2 => { if (shift1 != shift2 && this.isDurationOverlap(shift1, shift2)) { string name2 = getAssignVarName(employee, shift2); sumOverlapExpr.AddTerm(1.0, assignVars[name2]); } }); model.AddLe(sumOverlapExpr, 1.0, "MinRestConst"); sumAssignHourExpr.AddTerm((shift1.end - shift1.begin).TotalMinutes, assignVar1); }); }); //3) No overassignment constraint shifts.ForEach(shift => { ILinearNumExpr sumAssigsExpr = model.LinearNumExpr(); employees.ForEach(employee => { string name1 = getAssignVarName(employee, shift); IIntVar assignVar1 = assignVars[name1]; sumAssigsExpr.AddTerm(1.0, assignVar1); }); model.AddLe(sumAssigsExpr, shift.shiftNumber, "NoOverAssignConst"); }); model.AddEq(sumAssignHourExpr, 0.0, "TotalAssignedHourConst"); INumVar[] goalVars = { totalAssignHourVar }; double[] coeffs = { 1.0 }; model.AddMaximize(model.ScalProd(goalVars, coeffs)); model.ExportModel(@"C:\Users\user\Desktop\cplex log\model1.lp"); bool feasible = model.Solve(); if (feasible) { double objVal = model.ObjValue; model.Output().WriteLine("Solution value = " + model.ObjValue); shifts.ForEach(shift => { ILinearNumExpr sumAssigsExpr = model.LinearNumExpr(); employees.ForEach(employee => { string name = getAssignVarName(employee, shift); }); model.AddLe(sumAssigsExpr, shift.shiftNumber, "NoOverAssignConst"); }); } else { } } catch (System.Exception ex) { Response.ContentType = "application/json; charset=utf-8"; Response.Write(ex.Message); Response.End(); } writer.Close(); }
} // END CreateMasterILP public static void Main(string[] args) { try { string fileName = "../../../../examples/data/atsp.dat"; // Check the command line arguments if (args.Length != 1 && args.Length != 2) { Usage(); return; } if (!(args[0].Equals("0") || args[0].Equals("1"))) { Usage(); return; } bool sepFracSols = (args[0].ToCharArray()[0] == '0' ? false : true); if (sepFracSols) { System.Console.WriteLine("Benders' cuts separated to cut off: " + "Integer and fractional infeasible solutions."); } else { System.Console.WriteLine("Benders' cuts separated to cut off: " + "Only integer infeasible solutions."); } if (args.Length == 2) { fileName = args[1]; } // Read arc_costs from data file (17 city problem) Data data = new Data(fileName); // create master ILP int numNodes = data.numNodes; Cplex cplex = new Cplex(); IIntVar[][] x = new IIntVar[numNodes][]; CreateMasterILP(cplex, data, x); // Create workerLP for Benders' cuts separation WorkerLP workerLP = new WorkerLP(numNodes); // Set up the cut callback to be used for separating Benders' cuts cplex.SetParam(Cplex.Param.Preprocessing.Presolve, false); // Set the maximum number of threads to 1. // This instruction is redundant: If MIP control callbacks are registered, // then by default CPLEX uses 1 (one) thread only. // Note that the current example may not work properly if more than 1 threads // are used, because the callback functions modify shared global data. // We refer the user to the documentation to see how to deal with multi-thread // runs in presence of MIP control callbacks. cplex.SetParam(Cplex.Param.Threads, 1); // Turn on traditional search for use with control callbacks cplex.SetParam(Cplex.Param.MIP.Strategy.Search, Cplex.MIPSearch.Traditional); cplex.Use(new BendersLazyConsCallback(x, workerLP)); if (sepFracSols) { cplex.Use(new BendersUserCutCallback(x, workerLP)); } // Solve the model and write out the solution if (cplex.Solve()) { System.Console.WriteLine(); System.Console.WriteLine("Solution status: " + cplex.GetStatus()); System.Console.WriteLine("Objective value: " + cplex.ObjValue); if (cplex.GetStatus().Equals(Cplex.Status.Optimal)) { // Write out the optimal tour int i, j; double[][] sol = new double[numNodes][]; int[] succ = new int[numNodes]; for (j = 0; j < numNodes; ++j) { succ[j] = -1; } for (i = 0; i < numNodes; ++i) { sol[i] = cplex.GetValues(x[i]); for (j = 0; j < numNodes; ++j) { if (sol[i][j] > 1e-03) { succ[i] = j; } } } System.Console.WriteLine("Optimal tour:"); i = 0; while (succ[i] != 0) { System.Console.Write(i + ", "); i = succ[i]; } System.Console.WriteLine(i); } else { System.Console.WriteLine("Solution status is not Optimal"); } } else { System.Console.WriteLine("No solution available"); } workerLP.End(); cplex.End(); } catch (ILOG.Concert.Exception ex) { System.Console.WriteLine("Concert Error: " + ex); } catch (InputDataReader.InputDataReaderException ex) { System.Console.WriteLine("Data Error: " + ex); } catch (System.IO.IOException ex) { System.Console.WriteLine("IO Error: " + ex); } } // END Main
// This method creates the master ILP (arc variables x and degree constraints). // // Modeling variables: // forall (i,j) in A: // x(i,j) = 1, if arc (i,j) is selected // = 0, otherwise // // Objective: // minimize sum((i,j) in A) c(i,j) * x(i,j) // // Degree constraints: // forall i in V: sum((i,j) in delta+(i)) x(i,j) = 1 // forall i in V: sum((j,i) in delta-(i)) x(j,i) = 1 // // Binary constraints on arc variables: // forall (i,j) in A: x(i,j) in {0, 1} // internal static void CreateMasterILP(IModeler model, Data data, IIntVar[][] x) { int i, j; int numNodes = data.numNodes; // Create variables x(i,j) for (i,j) in A // For simplicity, also dummy variables x(i,i) are created. // Those variables are fixed to 0 and do not partecipate to // the constraints. for (i = 0; i < numNodes; ++i) { x[i] = new IIntVar[numNodes]; for (j = 0; j < numNodes; ++j) { x[i][j] = model.BoolVar("x." + i + "." + j); model.Add(x[i][j]); } x[i][i].UB = 0; } // Create objective function: minimize sum((i,j) in A ) c(i,j) * x(i,j) ILinearNumExpr objExpr = model.LinearNumExpr(); for (i = 0; i < numNodes; ++i) objExpr.Add(model.ScalProd(x[i], data.arcCost[i])); model.AddMinimize(objExpr); // Add the out degree constraints. // forall i in V: sum((i,j) in delta+(i)) x(i,j) = 1 for (i = 0; i < numNodes; ++i) { ILinearNumExpr expr = model.LinearNumExpr(); for (j = 0; j < i; ++j) expr.AddTerm(x[i][j], 1.0); for (j = i + 1; j < numNodes; ++j) expr.AddTerm(x[i][j], 1.0); model.AddEq(expr, 1.0); } // Add the in degree constraints. // forall i in V: sum((j,i) in delta-(i)) x(j,i) = 1 for (i = 0; i < numNodes; ++i) { ILinearNumExpr expr = model.LinearNumExpr(); for (j = 0; j < i; ++j) expr.AddTerm(x[j][i], 1.0); for (j = i + 1; j < numNodes; ++j) expr.AddTerm(x[j][i], 1.0); model.AddEq(expr, 1.0); } }
// Step 4 ***************************************************************************************************** // Step 4 ***************************************************************************************************** internal static void PopulateByRow(IMPModeler model, out IIntVar[][][] var2, out IIntVar[][][][] var3, out IIntVar[][][][][] var4, out IRange[][] rng, CRegion lscrg, CRegion sscrg, double[,] adblTD, string strAreaAggregation) { var aCph = lscrg.GetCphCol().ToArray(); int intCpgCount = lscrg.GetCphCount(); //double dblILPSmallValue = 0.000000001; //double dblILPSmallValue = 0; var x = new IIntVar[intCpgCount][][]; for (int i = 0; i < intCpgCount; i++) { x[i] = new IIntVar[intCpgCount][]; for (int j = 0; j < intCpgCount; j++) { x[i][j] = model.BoolVarArray(intCpgCount); } } //cost in terms of type change var y = Generate4DNumVar(model, intCpgCount - 1, intCpgCount, intCpgCount, intCpgCount); //cost in terms of compactness (length of interior boundaries) var z = Generate4DNumVar(model, intCpgCount - 2, intCpgCount, intCpgCount, intCpgCount); var c = Generate4DNumVar(model, intCpgCount - 2, intCpgCount, intCpgCount, intCpgCount); var3 = new IIntVar[1][][][]; var4 = new IIntVar[3][][][][]; var3[0] = x; var4[0] = y; var4[1] = z; var4[2] = c; //model.AddEq(x[2][0][3], 1.0, "X1"); //model.AddEq(x[2][1][3], 1.0, "X2"); //model.AddEq(x[2][2][2], 1.0, "X3"); //model.AddEq(x[2][3][3], 1.0, "X4"); //add minimizations ILinearNumExpr pTypeCostExpr = model.LinearNumExpr(); //ILinearNumExpr pTypeCostAssitantExpr = model.LinearNumExpr(); for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { for (int k = 0; k < intCpgCount; k++) { for (int l = 0; l < intCpgCount; l++) { double dblCoe = aCph[j].dblArea * adblTD[aCph[k].intTypeIndex, aCph[l].intTypeIndex]; pTypeCostExpr.AddTerm(y[i][j][k][l], dblCoe); //pTypeCostAssitantExpr.AddTerm(y[i][j][k][l], dblILPSmallValueMinimization); } } } } //this is actually for t=1, whose compactness is known double dblCompCostFirstPart = 0; ILinearNumExpr pCompCostSecondPartExpr = model.LinearNumExpr(); var pAdjCorrCphsSD = lscrg.AdjCorrCphsSD; double dblConst = Convert.ToDouble(intCpgCount - 1) / Convert.ToDouble(intCpgCount - 2); for (int i = 0; i < intCpgCount - 2; i++) //i represents indices { double dblNminusT = intCpgCount - i - 2; //double dblTemp = (intCpgCount - i) * dblConst; dblCompCostFirstPart += 1 / dblNminusT; double dblSecondPartDenominator = lscrg.dblInteriorSegLength * dblNminusT * 2; //we don't need to divide the value by 2 because every boundary is only counted once foreach (var pCorrCphs in pAdjCorrCphsSD.Keys) { for (int l = 0; l < intCpgCount; l++) { pCompCostSecondPartExpr.AddTerm(pCorrCphs.dblSharedSegLength / dblSecondPartDenominator, z[i][pCorrCphs.FrCph.ID][pCorrCphs.ToCph.ID][l]); pCompCostSecondPartExpr.AddTerm(pCorrCphs.dblSharedSegLength / dblSecondPartDenominator, z[i][pCorrCphs.ToCph.ID][pCorrCphs.FrCph.ID][l]); } } //var pSecondPartExpr = model.Prod(pCompCostSecondPartExpr, 1 / dblSecondPartDenominator); } if (intCpgCount == 1) { model.AddMinimize(pTypeCostExpr); //we just use an empty expression } else { //Our Model*************************************** var Ftp = model.Prod(pTypeCostExpr, 1 / lscrg.dblArea); var Fcp = model.Prod(dblConst, model.Sum(dblCompCostFirstPart, model.Negative(pCompCostSecondPartExpr))); //model.AddMinimize(model.Prod(model.Sum(Ftp, Fcp), 0.5)); model.AddMinimize(model.Sum( model.Prod(1 - CAreaAgg_Base.dblLamda, Ftp), model.Prod(CAreaAgg_Base.dblLamda, Fcp))); //model.AddMinimize(Fcp); //model.AddMaximize(Fcp); //model.AddObjective() } //for showing slacks var IRangeLt = new List <IRange>(); //a polygon $p$ is assigned to exactly one polygon at a step $t$ for (int i = 0; i < intCpgCount; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { ILinearNumExpr pOneCenterExpr = model.LinearNumExpr(); for (int l = 0; l < intCpgCount; l++) { pOneCenterExpr.AddTerm(x[i][j][l], 1.0); } model.AddEq(pOneCenterExpr, 1.0, "AssignToOnlyOneCenter"); } } //polygon $r$, which is assigned by other polygons, must be a center for (int i = 0; i < intCpgCount; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { for (int l = 0; l < intCpgCount; l++) { model.AddLe(x[i][j][l], x[i][l][l], "AssignedIsCenter__" + i + "__" + j + "__" + l); } } } //only one patch is aggregated into another patch at each step for (int i = 0; i < intCpgCount; i++) //i represents indices { ILinearNumExpr pOneAggregationExpr = model.LinearNumExpr(); for (int j = 0; j < intCpgCount; j++) { pOneAggregationExpr.AddTerm(x[i][j][j], 1.0); } model.AddEq(pOneAggregationExpr, intCpgCount - i, "CountCenters"); } //a center can disappear, but will never reappear afterwards for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { model.AddGe(x[i][j][j], x[i + 1][j][j], "SteadyCenters"); } } //to make sure that the final aggregated polygon has the same color as the target polygon ILinearNumExpr pFinalStateExpr = model.LinearNumExpr(); int intTypeIndexGoal = sscrg.GetSoloCphTypeIndex(); for (int i = 0; i < intCpgCount; i++) { if (aCph[i].intTypeIndex == intTypeIndexGoal) { pFinalStateExpr.AddTerm(x[intCpgCount - 1][i][i], 1.0); } } model.AddEq(pFinalStateExpr, 1.0, "EnsureTarget"); //to restrict *y* for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { for (int k = 0; k < intCpgCount; k++) { //IRangeLt.Add(model.AddLe(model.Sum(y[i][j][k][k], x[i][j][k], x[i + 1][j][k]), 2.0 , "RestrictY")); for (int l = 0; l < intCpgCount; l++) { var LieYRight = model.LinearIntExpr(-1); LieYRight.AddTerm(x[i][j][k], 1); LieYRight.AddTerm(x[i + 1][j][l], 1); model.AddGe(y[i][j][k][l], LieYRight, "RestrictY1"); model.AddLe(y[i][j][k][l], x[i][j][k], "RestrictY2"); model.AddLe(y[i][j][k][l], x[i + 1][j][l], "RestrictY3"); } } } } //to restrict *z* for (int i = 0; i < intCpgCount - 2; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { //for (int k = j; k < intCpgCount; k++) // pay attention for (int k = 0; k < intCpgCount; k++) { for (int l = 0; l < intCpgCount; l++) { var LieZRight = model.LinearIntExpr(-1); LieZRight.AddTerm(x[i + 1][j][l], 1); LieZRight.AddTerm(x[i + 1][k][l], 1); model.AddGe(z[i][j][k][l], LieZRight, "RestrictZ1"); model.AddLe(z[i][j][k][l], x[i + 1][j][l], "RestrictZ2"); model.AddLe(z[i][j][k][l], x[i + 1][k][l], "RestrictZ3"); } } } } //to restrict *c* double dblCpgCountReciprocal = 1 / Convert.ToDouble(intCpgCount); for (int i = 0; i < intCpgCount - 2; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { //for (int k = j; k < intCpgCount; k++) // pay attention for (int k = 0; k < intCpgCount; k++) { for (int l = 0; l < intCpgCount; l++) { if (k == l) { continue; } model.AddLe(c[i][j][k][l], x[i][j][k], "RestrictC1"); var pLieContiguityExpr = model.LinearIntExpr(); //pContiguityExpr.AddTerm(x[i][j][k], 1.0); //including polygon j itself foreach (var pAdjacentCph in aCph[j].AdjacentCphSS) { pLieContiguityExpr.AddTerm(x[i][pAdjacentCph.ID][l], 1); } model.AddLe(c[i][j][k][l], pLieContiguityExpr, "Contiguity"); foreach (var pAdjacentCph in aCph[j].AdjacentCphSS) { var pContiguityExpr2 = model.LinearNumExpr(-1); pContiguityExpr2.AddTerm(x[i][j][k], 1); pContiguityExpr2.AddTerm(x[i][pAdjacentCph.ID][l], 1); model.AddGe(c[i][j][k][l], pContiguityExpr2, "Contiguity2"); } var pContiguityExprRight3 = model.LinearIntExpr(); for (int m = 0; m < intCpgCount; m++) { pContiguityExprRight3.AddTerm(c[i][m][k][l], 1); } model.AddLe(y[i][k][k][l], pContiguityExprRight3, "Contiguity3"); } } } } //If two polygons have been aggregated into one polygon, then they will //be aggregated together in later steps. Our sixth constraint achieve this by requiring for (int i = 0; i < intCpgCount - 3; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { for (int k = 0; k < intCpgCount; k++) { var pAssignTogetherExprPre = model.LinearIntExpr(); var pAssignTogetherExprAfter = model.LinearIntExpr(); for (int l = 0; l < intCpgCount; l++) { pAssignTogetherExprPre.AddTerm(z[i][j][k][l], 1); pAssignTogetherExprAfter.AddTerm(z[i + 1][j][k][l], 1); } model.AddLe(pAssignTogetherExprPre, pAssignTogetherExprAfter, "AssignTogether"); } } } var2 = new IIntVar[1][][]; if (strAreaAggregation == _strSmallest) { IIntVar[][] w = new IIntVar[intCpgCount - 1][]; for (int i = 0; i < intCpgCount - 1; i++) { w[i] = model.BoolVarArray(intCpgCount); } var2[0] = w; //there is only one smallest patch will be involved in each aggregation step for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { var pOneSmallestExpr = model.LinearIntExpr(); for (int j = 0; j < intCpgCount; j++) { pOneSmallestExpr.AddTerm(w[i][j], 1); } model.AddEq(pOneSmallestExpr, 1.0, "OneSmallest"); } //forces that the aggregation must involve the smallest patch. for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { for (int j = 0; j < intCpgCount; j++) { var pInvolveSmallestExpr = model.LinearIntExpr(); for (int k = 0; k < intCpgCount; k++) { if (j == k) //o != r { continue; } pInvolveSmallestExpr.AddTerm(y[i][j][j][k], 1); pInvolveSmallestExpr.AddTerm(y[i][k][k][j], 1); } model.AddLe(w[i][j], pInvolveSmallestExpr, "InvolveSmallest"); } } //To guarantee that patch $o$ is involved in aggregation is indeed the smallest patch double dblM = 1.1 * lscrg.dblArea; //a very large value for (int i = 0; i < intCpgCount - 1; i++) //i represents indices { var aAreaExpr = ComputeAreaExpr(model, x[i], aCph); for (int j = 0; j < intCpgCount; j++) { for (int k = 0; k < intCpgCount; k++) { if (j == k) //o != r { continue; } var pSumExpr = model.Sum(2.0, model.Negative(model.Sum(w[i][j], x[i][k][k]))); //(2-w_{t,o}-x_{t,r,r}) var pProdExpr = model.Prod(pSumExpr, dblM); //M(2-w_{t,o}-x_{t,r,r}) //A_{t,o}-A_{t,r}<= M(2-w_{t,o}-x_{t,r,r}) model.AddLe(model .Sum(aAreaExpr[j], model.Negative(aAreaExpr[k])), pProdExpr, "IndeedSmallest"); } } } } //***************compare with number of constraints counted manually************ rng = new IRange[1][]; rng[0] = new IRange[IRangeLt.Count]; for (int i = 0; i < IRangeLt.Count; i++) { rng[0][i] = IRangeLt[i]; } }
} // END WorkerLP // This method creates the master ILP (arc variables x and degree constraints). // // Modeling variables: // forall (i,j) in A: // x(i,j) = 1, if arc (i,j) is selected // = 0, otherwise // // Objective: // minimize sum((i,j) in A) c(i,j) * x(i,j) // // Degree constraints: // forall i in V: sum((i,j) in delta+(i)) x(i,j) = 1 // forall i in V: sum((j,i) in delta-(i)) x(j,i) = 1 // // Binary constraints on arc variables: // forall (i,j) in A: x(i,j) in {0, 1} // internal static void CreateMasterILP(IModeler model, Data data, IIntVar[][] x) { int i, j; int numNodes = data.numNodes; // Create variables x(i,j) for (i,j) in A // For simplicity, also dummy variables x(i,i) are created. // Those variables are fixed to 0 and do not partecipate to // the constraints. for (i = 0; i < numNodes; ++i) { x[i] = new IIntVar[numNodes]; for (j = 0; j < numNodes; ++j) { x[i][j] = model.BoolVar("x." + i + "." + j); model.Add(x[i][j]); } x[i][i].UB = 0; } // Create objective function: minimize sum((i,j) in A ) c(i,j) * x(i,j) ILinearNumExpr objExpr = model.LinearNumExpr(); for (i = 0; i < numNodes; ++i) { objExpr.Add(model.ScalProd(x[i], data.arcCost[i])); } model.AddMinimize(objExpr); // Add the out degree constraints. // forall i in V: sum((i,j) in delta+(i)) x(i,j) = 1 for (i = 0; i < numNodes; ++i) { ILinearNumExpr expr = model.LinearNumExpr(); for (j = 0; j < i; ++j) { expr.AddTerm(x[i][j], 1.0); } for (j = i + 1; j < numNodes; ++j) { expr.AddTerm(x[i][j], 1.0); } model.AddEq(expr, 1.0); } // Add the in degree constraints. // forall i in V: sum((j,i) in delta-(i)) x(j,i) = 1 for (i = 0; i < numNodes; ++i) { ILinearNumExpr expr = model.LinearNumExpr(); for (j = 0; j < i; ++j) { expr.AddTerm(x[j][i], 1.0); } for (j = i + 1; j < numNodes; ++j) { expr.AddTerm(x[j][i], 1.0); } model.AddEq(expr, 1.0); } } // END CreateMasterILP
internal BendersUserCutCallback(IIntVar[][] x, WorkerLP workerLP) { this.x = x; this.workerLP = workerLP; numNodes = x.Length; }
// // Matrix operations // private static IIntVar[][] Transpose(IIntVar[][] x) { int m = x.Length; int n = x[0].Length; IIntVar[][] y = new IIntVar[n][]; for (int i = 0; i < n; i++) { y[i] = new IIntVar[m]; for (int j = 0; j < m; j++) y[i][j] = x[j][i]; } return y; }
// This method separates Benders' cuts violated by the current x solution. // Violated cuts are found by solving the worker LP // public IRange Separate(double[][] xSol, IIntVar[][] x) { int i, j, k; IRange cut = null; // Update the objective function in the worker LP: // minimize sum(k in V0) sum((i,j) in A) x(i,j) * v(k,i,j) // - sum(k in V0) u(k,0) + sum(k in V0) u(k,k) ILinearNumExpr objExpr = cplex.LinearNumExpr(); for (k = 1; k < numNodes; ++k) { for (i = 0; i < numNodes; ++i) { for (j = 0; j < numNodes; ++j) { objExpr.AddTerm(v[k-1][i][j], xSol[i][j]); } } } for (k = 1; k < numNodes; ++k) { objExpr.AddTerm(u[k-1][k], 1.0); objExpr.AddTerm(u[k-1][0], -1.0); } cplex.GetObjective().Expr = objExpr; // Solve the worker LP cplex.Solve(); // A violated cut is available iff the solution status is Unbounded if ( cplex.GetStatus().Equals(Cplex.Status.Unbounded) ) { // Get the violated cut as an unbounded ray of the worker LP ILinearNumExpr rayExpr = cplex.Ray; // Compute the cut from the unbounded ray. The cut is: // sum((i,j) in A) (sum(k in V0) v(k,i,j)) * x(i,j) >= // sum(k in V0) u(k,0) - u(k,k) ILinearNumExpr cutLhs = cplex.LinearNumExpr(); double cutRhs = 0.0; ILinearNumExprEnumerator rayEnum = rayExpr.GetLinearEnumerator(); while ( rayEnum.MoveNext() ) { INumVar var = rayEnum.NumVar; bool varFound = false; for (k = 1; k < numNodes && !varFound; ++k) { for (i = 0; i < numNodes && !varFound; ++i) { for (j = 0; j < numNodes && !varFound; ++j) { if ( var.Equals(v[k-1][i][j]) ) { cutLhs.AddTerm(x[i][j], rayEnum.Value); varFound = true; } } } } for (k = 1; k < numNodes && !varFound; ++k) { for (i = 0; i < numNodes && !varFound; ++i) { if ( var.Equals(u[k-1][i]) ) { if ( i == 0 ) cutRhs += rayEnum.Value; else if ( i == k ) cutRhs -= rayEnum.Value; varFound = true; } } } } cut = cplex.Ge(cutLhs, cutRhs); } return cut; }
static public void Main(string[] args) { CP cp = new CP(); int nbTruckConfigs = 7; // number of possible configurations for the truck int nbOrders = 21; int nbCustomers = 3; int nbTrucks = 15; //max number of travels of the truck int[] maxTruckConfigLoad = //Capacity of the truck depends on its config { 11, 11, 11, 11, 10, 10, 10 }; int maxLoad = Max(maxTruckConfigLoad); int[] customerOfOrder = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2 }; int[] volumes = { 3, 4, 3, 2, 5, 4, 11, 4, 5, 2, 4, 7, 3, 5, 2, 5, 6, 11, 1, 6, 3 }; int[] colors = { 1, 2, 0, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 0, 2, 1, 0, 2, 0, 0, 0 }; int[] truckCost = //cost for loading a truck of a given config { 2, 2, 2, 3, 3, 3, 4 }; //Decision variables IIntVar[] truckConfigs = cp.IntVarArray(nbTrucks, 0, nbTruckConfigs - 1); //configuration of the truck IIntVar[] where = cp.IntVarArray(nbOrders, 0, nbTrucks - 1); //In which truck is an order IIntVar[] load = cp.IntVarArray(nbTrucks, 0, maxLoad); //load of a truck IIntVar numUsed = cp.IntVar(0, nbTrucks); // number of trucks used IIntVar[] customerOfTruck = cp.IntVarArray(nbTrucks, 0, nbCustomers); // transition costs between trucks IIntTupleSet costTuples = cp.IntTable(3); cp.AddTuple(costTuples, new int[] { 0, 0, 0 }); cp.AddTuple(costTuples, new int[] { 0, 1, 0 }); cp.AddTuple(costTuples, new int[] { 0, 2, 0 }); cp.AddTuple(costTuples, new int[] { 0, 3, 10 }); cp.AddTuple(costTuples, new int[] { 0, 4, 10 }); cp.AddTuple(costTuples, new int[] { 0, 5, 10 }); cp.AddTuple(costTuples, new int[] { 0, 6, 15 }); cp.AddTuple(costTuples, new int[] { 1, 0, 0 }); cp.AddTuple(costTuples, new int[] { 1, 1, 0 }); cp.AddTuple(costTuples, new int[] { 1, 2, 0 }); cp.AddTuple(costTuples, new int[] { 1, 3, 10 }); cp.AddTuple(costTuples, new int[] { 1, 4, 10 }); cp.AddTuple(costTuples, new int[] { 1, 5, 10 }); cp.AddTuple(costTuples, new int[] { 1, 6, 15 }); cp.AddTuple(costTuples, new int[] { 2, 0, 0 }); cp.AddTuple(costTuples, new int[] { 2, 1, 0 }); cp.AddTuple(costTuples, new int[] { 2, 2, 0 }); cp.AddTuple(costTuples, new int[] { 2, 3, 10 }); cp.AddTuple(costTuples, new int[] { 2, 4, 10 }); cp.AddTuple(costTuples, new int[] { 2, 5, 10 }); cp.AddTuple(costTuples, new int[] { 2, 6, 15 }); cp.AddTuple(costTuples, new int[] { 3, 0, 3 }); cp.AddTuple(costTuples, new int[] { 3, 1, 3 }); cp.AddTuple(costTuples, new int[] { 3, 2, 3 }); cp.AddTuple(costTuples, new int[] { 3, 3, 0 }); cp.AddTuple(costTuples, new int[] { 3, 4, 10 }); cp.AddTuple(costTuples, new int[] { 3, 5, 10 }); cp.AddTuple(costTuples, new int[] { 3, 6, 15 }); cp.AddTuple(costTuples, new int[] { 4, 0, 3 }); cp.AddTuple(costTuples, new int[] { 4, 1, 3 }); cp.AddTuple(costTuples, new int[] { 4, 2, 3 }); cp.AddTuple(costTuples, new int[] { 4, 3, 10 }); cp.AddTuple(costTuples, new int[] { 4, 4, 0 }); cp.AddTuple(costTuples, new int[] { 4, 5, 10 }); cp.AddTuple(costTuples, new int[] { 4, 6, 15 }); cp.AddTuple(costTuples, new int[] { 5, 0, 3 }); cp.AddTuple(costTuples, new int[] { 5, 1, 3 }); cp.AddTuple(costTuples, new int[] { 5, 2, 3 }); cp.AddTuple(costTuples, new int[] { 5, 3, 10 }); cp.AddTuple(costTuples, new int[] { 5, 4, 10 }); cp.AddTuple(costTuples, new int[] { 5, 5, 0 }); cp.AddTuple(costTuples, new int[] { 5, 6, 15 }); cp.AddTuple(costTuples, new int[] { 6, 0, 3 }); cp.AddTuple(costTuples, new int[] { 6, 1, 3 }); cp.AddTuple(costTuples, new int[] { 6, 2, 3 }); cp.AddTuple(costTuples, new int[] { 6, 3, 10 }); cp.AddTuple(costTuples, new int[] { 6, 4, 10 }); cp.AddTuple(costTuples, new int[] { 6, 5, 10 }); cp.AddTuple(costTuples, new int[] { 6, 6, 0 }); IIntVar[] transitionCost = cp.IntVarArray(nbTrucks - 1, 0, 1000); for (int i = 1; i < nbTrucks; i++) { IIntVar[] auxVars = new IIntVar[3]; auxVars[0] = truckConfigs[i - 1]; auxVars[1] = truckConfigs[i]; auxVars[2] = transitionCost[i - 1]; cp.Add(cp.AllowedAssignments(auxVars, costTuples)); } // constrain the volume of the orders in each truck cp.Add(cp.Pack(load, where, volumes, numUsed)); for (int i = 0; i < nbTrucks; i++) { cp.Add(cp.Le(load[i], cp.Element(maxTruckConfigLoad, truckConfigs[i]))); } // compatibility between the colors of an order and the configuration of its truck int[][] allowedContainerConfigs = new int[3][]; allowedContainerConfigs[0] = new int[] { 0, 3, 4, 6 }; allowedContainerConfigs[1] = new int[] { 1, 3, 5, 6 }; allowedContainerConfigs[2] = new int[] { 2, 4, 5, 6 }; for (int j = 0; j < nbOrders; j++) { IIntVar configOfContainer = cp.IntVar(allowedContainerConfigs[colors[j]]); cp.Add(cp.Eq(configOfContainer, cp.Element(truckConfigs, where[j]))); } // only one customer per truck for (int j = 0; j < nbOrders; j++) { cp.Add(cp.Eq(cp.Element(customerOfTruck, where[j]), customerOfOrder[j])); } // non used trucks are at the end for (int j = 1; j < nbTrucks; j++) { cp.Add(cp.Or(cp.Gt(load[j - 1], 0), cp.Eq(load[j], 0))); } // Dominance: the non used trucks keep the last used configuration cp.Add(cp.Gt(load[0], 0)); for (int i = 1; i < nbTrucks; i++) { cp.Add(cp.Or(cp.Gt(load[i], 0), cp.Eq(truckConfigs[i], truckConfigs[i - 1]))); } //Dominance: regroup deliveries with same configuration for (int i = nbTrucks - 2; i > 0; i--) { IConstraint Ct = cp.TrueConstraint(); for (int p = i + 1; p < nbTrucks; p++) { Ct = cp.And(cp.Neq(truckConfigs[p], truckConfigs[i - 1]), Ct); } cp.Add(cp.Or(cp.Eq(truckConfigs[i], truckConfigs[i - 1]), Ct)); } // Objective: first criterion for minimizing the cost for configuring and loading trucks // second criterion for minimizing the number of trucks IIntExpr obj1 = cp.Constant(0); for (int i = 0; i < nbTrucks; i++) { obj1 = cp.Sum(obj1, cp.Prod(cp.Element(truckCost, truckConfigs[i]), cp.Neq(load[i], 0))); } obj1 = cp.Sum(obj1, cp.Sum(transitionCost)); IIntExpr obj2 = numUsed; // Multicriteria lexicographic optimization cp.Add(cp.Minimize(cp.StaticLex(obj1, obj2))); cp.SetParameter(CP.DoubleParam.TimeLimit, 20); cp.SetParameter(CP.IntParam.LogPeriod, 50000); cp.Solve(); double[] obj = cp.GetObjValues(); Console.WriteLine("Configuration cost: " + (int)obj[0] + " Number of Trucks: " + (int)obj[1]); for (int i = 0; i < nbTrucks; i++) { if (cp.GetValue(load[i]) > 0) { Console.Write("Truck " + i + ": Config=" + cp.GetIntValue(truckConfigs[i]) + " Items= "); for (int j = 0; j < nbOrders; j++) { if (cp.GetValue(where[j]) == i) { Console.Write("<" + j + "," + colors[j] + "," + volumes[j] + "> "); } } Console.WriteLine(); } } }
static void Main(string[] args) { CP cp = new CP(); int weightSum = 0; for (int o = 0; o < nbOrders; o++) { weightSum += weight[o]; } IIntVar[] where = new IIntVar[nbOrders]; for (int o = 0; o < nbOrders; o++) { where[o] = cp.IntVar(0, nbSlabs - 1); } IIntVar[] load = new IIntVar[nbSlabs]; for (int m = 0; m < nbSlabs; m++) { load[m] = cp.IntVar(0, weightSum); } // Pack constraint cp.Add(cp.Pack(load, where, weight)); // Color constraints for (int m = 0; m < nbSlabs; m++) { IIntExpr[] colorExpArray = new IIntExpr[nbColors]; for (int c = 0; c < nbColors; c++) { IConstraint orCt = cp.FalseConstraint(); for (int o = 0; o < nbOrders; o++) { if (colors[o] == c) { orCt = cp.Or(orCt, cp.Eq(where[o], m)); } } colorExpArray[c] = cp.IntExpr(orCt); } cp.Add(cp.Le(cp.Sum(colorExpArray), 2)); } // Objective function int sizeLossValues = capacities[capacities.Length - 1] - capacities[0] + 1; int[] lossValues = new int[sizeLossValues]; lossValues[0] = 0; int indexValue = 1; for (int q = 1; q < capacities.Length; q++) { for (int p = capacities[q - 1] + 1; p <= capacities[q]; p++) { lossValues[indexValue] = capacities[q] - p; indexValue++; } } IIntExpr obj = cp.Constant(0); for (int m = 0; m < nbSlabs; m++) { obj = cp.Sum(obj, cp.Element(lossValues, load[m])); } cp.Add(cp.Minimize(obj)); // - A symmetry breaking constraint that is useful for small instances for (int m = 1; m < nbSlabs; m++) { cp.Add(cp.Ge(load[m - 1], load[m])); } if (cp.Solve()) { Console.WriteLine("Optimal value: " + cp.GetValue(obj)); for (int m = 0; m < nbSlabs; m++) { int p = 0; for (int o = 0; o < nbOrders; o++) { if (cp.GetValue(where[o]) == m) { ++p; } } if (p == 0) { continue; } Console.Write("Slab " + m + " is used for order"); if (p > 1) { Console.Write("s"); } Console.Write(" :"); for (int o = 0; o < nbOrders; o++) { if (cp.GetValue(where[o]) == m) { Console.Write(" " + o); } } Console.WriteLine(); } } }
static void Main(string[] args) { try { int n = 10; if (args.Length > 0) { n = Int32.Parse(args[0]); } if ((n % 2) == 1) { n++; } Console.WriteLine("Finding schedule for {0} teams", n); int nbWeeks = 2 * (n - 1); int nbGamesPerWeek = n / 2; int nbGames = n * (n - 1); CP cp = new CP(); IIntVar[][] games = new IIntVar[nbWeeks][]; IIntVar[][] home = new IIntVar[nbWeeks][]; IIntVar[][] away = new IIntVar[nbWeeks][]; for (int i = 0; i < nbWeeks; i++) { home[i] = cp.IntVarArray(nbGamesPerWeek, 0, n - 1); away[i] = cp.IntVarArray(nbGamesPerWeek, 0, n - 1); games[i] = cp.IntVarArray(nbGamesPerWeek, 0, nbGames - 1); } // // For each play slot, set up correspondance between game id, // home team, and away team // IIntTupleSet gha = cp.IntTable(3); int[] tuple = new int[3]; for (int i = 0; i < n; i++) { tuple[0] = i; for (int j = 0; j < n; j++) { if (i != j) { tuple[1] = j; tuple[2] = Game(i, j, n); cp.AddTuple(gha, tuple); } } } for (int i = 0; i < nbWeeks; i++) { for (int j = 0; j < nbGamesPerWeek; j++) { IIntVar[] vars = cp.IntVarArray(3); vars[0] = home[i][j]; vars[1] = away[i][j]; vars[2] = games[i][j]; cp.Add(cp.AllowedAssignments(vars, gha)); } } // // All teams play each week // for (int i = 0; i < nbWeeks; i++) { IIntVar[] teamsThisWeek = cp.IntVarArray(n); for (int j = 0; j < nbGamesPerWeek; j++) { teamsThisWeek[j] = home[i][j]; teamsThisWeek[nbGamesPerWeek + j] = away[i][j]; } cp.Add(cp.AllDiff(teamsThisWeek)); } // // Dual representation: for each game id, the play slot is maintained // IIntVar[] weekOfGame = cp.IntVarArray(nbGames, 0, nbWeeks - 1); IIntVar[] allGames = cp.IntVarArray(nbGames); IIntVar[] allSlots = cp.IntVarArray(nbGames, 0, nbGames - 1); for (int i = 0; i < nbWeeks; i++) { for (int j = 0; j < nbGamesPerWeek; j++) { allGames[i * nbGamesPerWeek + j] = games[i][j]; } } cp.Add(cp.Inverse(allGames, allSlots)); for (int i = 0; i < nbGames; i++) { cp.Add(cp.Eq(weekOfGame[i], cp.Div(allSlots[i], nbGamesPerWeek))); } // // Two half schedules. Cannot play the same pair twice in the same half. // Plus, impose a minimum number of weeks between two games involving // the same teams (up to six weeks) // int mid = nbWeeks / 2; int overlap = 0; if (n >= 6) { overlap = min(n / 2, 6); } for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int g1 = Game(i, j, n); int g2 = Game(j, i, n); cp.Add(cp.Equiv(cp.Ge(weekOfGame[g1], mid), cp.Lt(weekOfGame[g2], mid))); // Six week difference... if (overlap != 0) { cp.Add(cp.Ge(cp.Abs(cp.Diff(weekOfGame[g1], weekOfGame[g2])), overlap)); } } } // // Can't have three homes or three aways in a row. // IIntVar[][] playHome = new IIntVar[n][]; for (int i = 0; i < n; i++) { playHome[i] = cp.IntVarArray(nbWeeks, 0, 1); for (int j = 0; j < nbWeeks; j++) { cp.Add(cp.Eq(playHome[i][j], cp.Count(home[j], i))); } for (int j = 0; j < nbWeeks - 3; j++) { IIntVar[] window = cp.IntVarArray(3); for (int k = j; k < j + 3; k++) { window[k - j] = playHome[i][k]; } IIntExpr windowSum = cp.Sum(window); cp.Add(cp.Le(1, windowSum)); cp.Add(cp.Le(windowSum, 2)); } } // // If we start the season home, we finish away and vice versa. // for (int i = 0; i < n; i++) { cp.Add(cp.Neq(playHome[i][0], playHome[i][nbWeeks - 1])); } // // Objective: minimize the number of `breaks'. A break is // two consecutive home or away matches for a // particular team IIntVar[] teamBreaks = cp.IntVarArray(n, 0, nbWeeks / 2); for (int i = 0; i < n; i++) { IIntExpr nbreaks = cp.Constant(0); for (int j = 1; j < nbWeeks; j++) { nbreaks = cp.Sum(nbreaks, cp.IntExpr(cp.Eq(playHome[i][j - 1], playHome[i][j]))); } cp.Add(cp.Eq(teamBreaks[i], nbreaks)); } IIntVar breaks = cp.IntVar(n - 2, n * (nbWeeks / 2)); cp.Add(cp.Eq(breaks, cp.Sum(teamBreaks))); cp.Add(cp.Minimize(breaks)); // // Catalyzing constraints // // Each team plays home the same number of times as away for (int i = 0; i < n; i++) { cp.Add(cp.Eq(cp.Sum(playHome[i]), nbWeeks / 2)); } // Breaks must be even for each team for (int i = 0; i < n; i++) { cp.Add(cp.Eq(cp.Modulo(teamBreaks[i], 2), 0)); } // // Symmetry breaking constraints // // Teams are interchangeable. Fix first week. // Also breaks reflection symmetry of the whole schedule. for (int i = 0; i < nbGamesPerWeek; i++) { cp.Add(cp.Eq(home[0][i], i * 2)); cp.Add(cp.Eq(away[0][i], i * 2 + 1)); } // Order of games in each week is arbitrary. // Break symmetry by forcing an order. for (int i = 0; i < nbWeeks; i++) { for (int j = 1; j < nbGamesPerWeek; j++) { cp.Add(cp.Gt(games[i][j], games[i][j - 1])); } } cp.SetParameter(CP.DoubleParam.TimeLimit, 20); cp.SetParameter(CP.IntParam.LogPeriod, 10000); IVarSelector varSel = cp.SelectSmallest(cp.VarIndex(allGames));; IValueSelector valSel = cp.SelectRandomValue(); ISearchPhase phase = cp.SearchPhase(allGames, cp.IntVarChooser(varSel), cp.IntValueChooser(valSel)); cp.SetSearchPhases(phase); cp.StartNewSearch(); while (cp.Next()) { Console.WriteLine("Solution at {0}", cp.GetValue(breaks)); } cp.EndSearch(); } catch (ILOG.Concert.Exception e) { Console.WriteLine("Error {0}", e); } }
private void BuildModel() { // Create the decision variables, cost, and the model scene = new IIntVar[numScenes]; for (int s = 0; s < numScenes; s++) scene[s] = cp.IntVar(0, numScenes - 1); // Expression representing the global cost idleCost = cp.IntExpr(); // Make the slot-based secondary model IIntVar[] slot = new IIntVar[numScenes]; for (int s = 0; s < numScenes; s++) slot[s] = cp.IntVar(0, numScenes - 1); cp.Add(cp.Inverse(scene, slot)); // Loop over all actors, building cost for (int a = 0; a < numActors; a++) { // Expression for the waiting time for this actor IIntExpr actorWait = cp.IntExpr(); // Calculate the first and last slots where this actor plays List<IIntVar> position = new List<IIntVar>(); System.Collections.IEnumerator en = actorInScene[a].GetEnumerator(); while (en.MoveNext()) position.Add(slot[(int)en.Current]); IIntExpr firstSlot = cp.Min(position.ToArray()); IIntExpr lastSlot = cp.Max(position.ToArray()); // If an actor is not in a scene, he waits // if he is on set when the scene is filmed for (int s = 0; s < numScenes; s++) { if (!actorInScene[a].Contains(s)) { // not in scene IIntExpr wait = cp.And(cp.Le(firstSlot, slot[s]), cp.Le( slot[s], lastSlot)); actorWait = cp.Sum(actorWait, cp.Prod(sceneDuration[s], wait)); } } // Accumulate the cost of waiting time for this actor idleCost = cp.Sum(idleCost, cp.Prod(actorPay[a], actorWait)); } cp.Add(cp.Minimize(idleCost)); }