Beispiel #1
0
        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);
            }
        }
Beispiel #2
0
        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 ****");
            }
        }
Beispiel #3
0
        /*
         * MakeTeamTuples return a IIntTupleSet containing all the possible configurations of a team.
         * The team members in a tuple are ordered to break symmetry.
         */
        public static IIntTupleSet MakeTeamTuples(CP mainCP)
        {
            CP  cp = new CP();
            int i;

            int[] newEmployee = new int[nbPersons];
            int[] service     = new int[nbPersons];
            for (i = 0; i < nbPersons; i++)
            {
                if ((i % 2) == 0)
                {
                    newEmployee[i] = 1;
                }
                else
                {
                    newEmployee[i] = 0;
                }
                if (i < 20)
                {
                    service[i] = 0;
                }
                else if (i < 40)
                {
                    service[i] = 1;
                }
                else if (i < 45)
                {
                    service[i] = 2;
                }
                else if (i < 50)
                {
                    service[i] = 3;
                }
                else if (i < 55)
                {
                    service[i] = 4;
                }
                else
                {
                    service[i] = 5;
                }
            }

            IIntTupleSet ts = mainCP.IntTable(teamSize);

            IIntVar[] teamMembers = cp.IntVarArray(teamSize, 0, nbPersons - 1);

            //number of new employees among the teamMembers = number of teamMembers / 2
            IIntExpr nbNewEmployees = cp.Constant(0);

            for (i = 0; i < teamSize; i++)
            {
                nbNewEmployees = cp.Sum(nbNewEmployees, cp.Element(newEmployee, teamMembers[i]));
            }
            cp.Add(cp.Eq(nbNewEmployees, teamSize / 2));

            //a new employee and his coach must be in the same team
            for (i = 0; i < 60; i += 2)
            {
                if (coaching[i] >= 0)
                {
                    cp.Add(cp.Eq(cp.Count(teamMembers, i), cp.Count(teamMembers, coaching[i])));
                }
            }

            IIntVar[] serviceVar = cp.IntVarArray(teamSize, 0, numServices - 1);
            for (i = 0; i < teamSize; i++)
            {
                cp.Add(cp.Eq(serviceVar[i], cp.Element(service, teamMembers[i])));
            }

            // at most 4 people of the same service
            for (i = 0; i < numServices; i++)
            {
                cp.Add(cp.Le(cp.Count(serviceVar, i), 4));
            }

            //Persons of Services A and B cannot be in the same team
            //Persons of Services E and F cannot be in the same team
            cp.Add(cp.Or(cp.Eq(cp.Count(serviceVar, 0), 0), cp.Eq(cp.Count(serviceVar, 1), 0)));
            cp.Add(cp.Or(cp.Eq(cp.Count(serviceVar, 4), 0), cp.Eq(cp.Count(serviceVar, 5), 0)));

            // order the teamMembers to break symmetry
            for (i = 0; i < teamSize - 1; i++)
            {
                cp.Add(cp.Lt(teamMembers[i], teamMembers[i + 1]));
            }

            int[] tuple = new int[teamSize];

            cp.SetParameter(CP.IntParam.LogVerbosity,
                            CP.ParameterValues.Quiet);
            cp.SetParameter(CP.IntParam.SearchType,
                            CP.ParameterValues.DepthFirst);
            cp.StartNewSearch();
            while (cp.Next())
            {
                for (i = 0; i < teamSize; i++)
                {
                    tuple[i] = (int)cp.GetValue(teamMembers[i]);
                }
                cp.AddTuple(ts, tuple);
            }
            return(ts);
        }
Beispiel #4
0
        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();
                }
            }
        }