0

I am trying to model a problem with Choco to get the combinations of possible matchups in a tennis event (or any sport).

The way I am trying to do it I have the following:

// Set of timeslots when the event is held (i.e. 10am-10pm)
int nTimeslots = 12;

// Courts available: court #1, #2 and #3
int nCourts = 3;

String[] players = { "Novak", "Andy", "Roger", "Stan", "Rafel", "Kei", "Tomas", "David" };
int nPlayers = players.length;

// Timeslots when each player cannot play for whatever reason
int[][] unavailability = {
    { 0, 1, 5 },
    { 8, 10, 11 },
    { 1, 2, 11 },
    { 0, 1 },
    { 2, 3, 4, 5, 6 },
    { 3, 4, 9, 10, 11 },
    { 4, 5 },
    { 2, 3 }
};

// Number of timeslots each match will occupy
int matchDuration = 2;

// This will hold the final combinations
// rows -> players, columns -> timeslots, matches[i][j] -> court where the player plays at that timeslot (0 means the player does not play at that time)
IntVar[][] matches;

My main problem is that with this setup I cannot think of a way of defining my problem. I have been spending days on this to no success. I have seem slighly similar problems but the amount of different elements that ought to be combined are less, normally 1 or 2, but in my problem there are 3: players, timeslots and courts.

After expending a lot of time on this, I couldn't get further than this:

for (int player = 0; player < nPlayers; player++) {
    for (int timeslot = 0; timeslot < nTimeslots; timeslot++) {
        for (int playerUnavailbleTimeslot : unavailability[player]) {
            if (playerUnavailbleTimeslot != timeslot) {
                solver.post(IntConstraintFactory.arithm(matches[player][playerUnavailbleTimeslot], ">=", 0));
            } else {
                for (int i = 0; i < matchDuration; i++)
                    if (playerUnavailbleTimeslot - i >= 0)
                        solver.post(IntConstraintFactory.arithm(matches[player][playerUnavailbleTimeslot - i], "=", 0));
            }
        }
    }
}

IntVar matchesSum = VariableFactory.enumerated("Matches sum", 1 * matchDuration, nCourts * matchDuration, solver);
for (int player = 0; player < nPlayers; player++) {
    solver.post(IntConstraintFactory.sum(matches[player], matchesSum));
    //solver.post(IntConstraintFactory.nvalues(matches[player], VariableFactory.fixed(2, solver)));
}

The first double loop just forces to 0 those timeslots where the player is unavailable (plus the range based on the value of the match duration), and greater or equal to if he is available. That way the final matrix starts looking like this:

0 0 ? ? ? 0 ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? 0 0 0 0 ?
.........................

Then I just ensure than the sum of the values in each player's timeslots is between the court with the lowest number multiplied by the match duration and the court with the highest number multiplied by the match duration. This is one of the constraints I thought of so each row looks like this, for example, player 0 plays in court 2 at the timeslots 3 and 4:

0 0 0 2 2 0 0 0 0 0 0 0 

I tried defining the constraint nvalues that is supposed to enforced that no more than n different values conform the array, but if I use it like you can see above the problem just renders one solution (what?!).

However I need to define more constraints I don't even know how to start:

  • For each row the court where the player plays must have consecutive numbers if indeed that court is assigned
  • For each row I can only have 0s and the court number [1 - nCourts]
  • Columns should pair up to create the matches between a pair of players.
  • The same court cannot be paired up more than once for the same timeslot range (meaning not more than one match can take place in the court at the same time)

This is all I can think of in terms of constraints but I am sure there are more.

I would love any suggestion to help me continue doing this because right now I feel absolutely clueless and there is virtually zero information about Choco online to help me clear this up.

dabadaba
  • 9,064
  • 21
  • 85
  • 155

1 Answers1

3

I would start with writing down in math what you want.

Not sure if this is helpful, but here is my implementation, solving it as a mathematical programming problem. It is not using Constraint Programming but things can look similar to what you would do in Choco:

enter image description here

I try to maximize the minimum number of games of a player, so we don't have someone playing zero games. One could think of many variations, such as not playing against the same person all the time etc.

The results look like:

enter image description here

The numbers in the table are the court numbers (-1 means not allowed). In this schedule everyone plays three times.

Erwin Kalvelagen
  • 15,677
  • 2
  • 14
  • 39
  • This is a big help. Although I have some trouble trying to figure out what some of the variables and the equations are for. How did you implement it? Can you shed some light on how to do it in Choco? Again, thank you very much, you put quite some work on that answer and it definetly helps. However, why are some players playing more than one match? Or that just represents all the possible combinations? – dabadaba Mar 03 '16 at 15:21
  • I don't know much about Choco. The multiple matches is an invention by me. My objective is to schedule as many matches as possible (well, to be precise to maximize the minimum number of matches). This is easily replaced by something much more boring such as a constraint that requires exactly one match for each person (or something related). – Erwin Kalvelagen Mar 03 '16 at 15:34
  • Could I make it so it can either work as you intented and also restrict it for just one match per player? (that way it would work for both round-robin events and single-elimination events). I want to ask about the "Twoslots1" and "Twoslots2" equations. What are they intended for? Why are there two of them? Not that in my original problem the `matchDuration` is a variable so the matches are not meant to range `2` slots for `matchDuration` slots. – dabadaba Mar 03 '16 at 15:38
  • It is not really possible to maximize the number of matches per player and at the same time fixing the same thing to one. (At least it does not make much sense to me). – Erwin Kalvelagen Mar 03 '16 at 15:40
  • 1
    Twoslots1 maps between the start of a match (denoted by g) and the two corresponding x's (x indicates when someone plays). Twoslots2 says a match cannot start at t and at t+1. I assume each match takes two consecutive periods (see the results). – Erwin Kalvelagen Mar 03 '16 at 15:45
  • About the first comment: ok I get it doesn't make sense mathematically. But I guess I could just branch my code and apply one constraint or the other depending on the type of tournament :) – dabadaba Mar 03 '16 at 15:52
  • About the second comment: I kind of understand it know, thank you. But would it be possible to move the consecutive periods into another variable (instead of assuming its value is 2)? If possible, how would the equations change (I assume it'd only affect the Twoslots1 and Twoslots2 equations). – dabadaba Mar 03 '16 at 15:52
  • Yes, this can be reformulated to handle any given number. Also the nonlinearity can be linearized to allow faster solvers. – Erwin Kalvelagen Mar 03 '16 at 17:36
  • Thank you. I am trying to implement this right now with Choco. I am still confused by one of the explanations you mentioned earlier though. Twoslots2 says that a match can't start at t and t+1. I assume this is to prevent matches from overlapping? But how does the equation ensure that? – dabadaba Mar 03 '16 at 17:45
  • (continuing previous comment) I want to reformulate Twoslots1 and 2 so the match duration is a variable, not 2. For Twoslots1 I guess I could just loop x from t to t+matchDuration and ensure that g_p,c,t equals to that accumalated value. Am I correct? But how about for Twslots2? Doing the same kind of loop in a sum wouldn't end up in a 0 or 1 value. How could I achieve the same idea? Thank you very very much for these answers. You are literally the only person helping me since I started this project weeks ago. – dabadaba Mar 03 '16 at 17:47