Proceedings of the 2018 XCSP3 Competition

12/17/2018 ∙ by Christophe Lecoutre, et al. ∙ 0

This document represents the proceedings of the 2018 XCSP3 Competition. The results of this competition of constraint solvers were presented at CP'18, the 24th International Conference on Principles and Practice of Constraint Programming, held in Lille, France from 27th August 2018 to 31th August, 2018.

READ FULL TEXT VIEW PDF
POST COMMENT

Comments

There are no comments yet.

Authors

This week in AI

Get the week's most popular data science and artificial intelligence research sent straight to your inbox every Saturday.

2.1 Auction

This is Problem 063 on CSPLib, called Winner Determination Problem (Combinatorial Auction).

Description (from Patrick Prosser on CSPLib)

“There is a bunch of people bidding for things. A bid has a value, and the bid is for a set of items. If we have two bids, call them A and B, and there is an intersection on the items they bid for, then we can accept bid A or bid B, but we cannot accept both of them. However, if A and B are bids on disjoint sets of items then these two bids are compatible with each other, and we might accept both. The problem then is to accept compatible bids such that we maximize the sum of the values of those bids.”

Data

As an illustration of data specifying an instance of this problem, we have:

{
  "bids": [
    { "value": 10, "items": [1, 2] },
    { "value": 20, "items": [1, 3] },
    { "value": 30, "items": [2, 4] },
    { "value": 40, "items": [2, 3, 4] },
    { "value": 14, "items": [1] }
  ]
}

Model

The MCSP3 model used for the competition is:

class Auction implements ProblemAPI {
  Bid[] bids;
  class Bid {
    int value;
    int[] items;
  }
  public void model() {
    int[] allItems = singleValuesFrom(bids, bid -> bid.items); //distinct sorted items
    int[] bidValues = valuesFrom(bids, bid -> bid.value);
    int nBids = bids.length, nItems = allItems.length;
    Var[] b = array(”b”, size(nBids), dom(0, 1),
      ”b[i] is 1 iff the ith bid is selected”);
    forall(range(nItems), i -> {
      int[] itemBids = select(range(nBids), j -> contains(bids[j].items, allItems[i]));
      if (itemBids.length > 1) {
        Var[] scope = select(b, itemBids);
        if (modelVariant(”cnt”))
          atMost1(scope, takingValue(1));
        if (modelVariant(”sum”))
          sum(scope, LE, 1);
      }
    }).note(”avoiding intersection of bids”);
    maximize(SUM, b, weightedBy(bidValues))
      .note(”maximizing summed value of selected bids”);
  }
}

The model is rather elementary, involving 0/1 variables, and either the global constraint count (atMost1) with model variant ’cnt’, or the global constraint sum with model variant ’sum’. To observe the efficiency of solvers with respect to these two global constraints, two series of 10 instances have been selected for the competition. Also, note that only the model variant ’sum’ is compatible with the restrictions imposed for the mini-track.

2.2 Bacp

This is Problem 030 on CSPLib, called Balanced Academic Curriculum Problem (BACP).

Description (from Brahim Hnich, Zeynep Kiziltan and Toby Walsh on CSPLib)

“The BACP is to design a balanced academic curriculum by assigning periods to courses in a way that the academic load of each period is balanced, i.e., as similar as possible. An academic curriculum is defined by a set of courses and a set of prerequisite relationships among them. Courses must be assigned within a maximum number of academic periods. Each course has associated a number of credits or units that represent the academic effort required to successfully follow it. The curriculum must obey the following regulations:

  • Minimum academic load: a minimum number of academic credits per period is required to consider a student as full time.

  • Maximum academic load: a maximum number of academic credits per period is allowed in order to avoid overload.

  • Minimum number of courses: a minimum number of courses per period is required to consider a student as full time.

  • Maximum number of courses: a maximum number of courses per period is allowed in order to avoid overload.

The goal is to assign a period to every course in a way that the minimum and maximum academic load for each period, the minimum and maximum number of courses for each period, and the prerequisite relationships are satisfied. An optimal balanced curriculum minimizes the maximum academic load for all periods.”

Data

As an illustration of data specifying an instance of this problem, we have:

{
  "nPeriods": 5,
  "minCredits": 6,
  "maxCredits": 15,
  "minCourses": 2,
  "maxCourses": 6,
  "credits": [2, 3, 2, 4, 1, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3],
  "prerequisites": [[6,0], [7,5], [10,4], [10,5], [11,10], [13,8], [14,8], [15,9]]
}

Model

The MCSP3 model used for the competition is:

class Bacp implements ProblemAPI {
  int nPeriods;
  int minCredits, maxCredits;
  int minCourses, maxCourses;
  int[] credits;
  int[][] prerequisites;
  private int[][] channelingTable(int c) {
    int[][] tuples = new int[nPeriods][nPeriods + 1];
    for (int p = 0; p < nPeriods; p++) {
      tuples[p][p] = credits[c];
      tuples[p][nPeriods] = p;
    }
    return tuples;
  }
  public void model() {
    int nCourses = credits.length, nPrerequisites = prerequisites.length;
    Var[] s = array(”s”, size(nCourses), dom(range(nPeriods)),
      ”s[c] is the period (schedule) for course c”);
    Var[] co = array(”co”, size(nPeriods), dom(range(minCourses, maxCourses + 1)),
      ”co[p] is the number of courses at period p”);
    Var[] cr = array(”cr”, size(nPeriods), dom(range(minCredits, maxCredits + 1)),
      ”cr[p] is the number of credits at period p”);
    Var[][] cp = array(”cp”, size(nCourses, nPeriods), (c, p) -> dom(0, credits[c]),
      ”cp[c][p] is 0 if course c is not planned at period p, the number of credits for c otherwise”);
    forall(range(nCourses), c -> extension(vars(cp[c], s[c]), channelingTable(c)))
      .note(”channeling between arrays cp and s”);
    forall(range(nPeriods), p -> count(s, takingValue(p), EQ, co[p]))
      .note(”counting the number of courses in each period”);
    forall(range(nPeriods), p -> sum(columnOf(cp, p), EQ, cr[p]))
      .note(”counting the number of credits in each period”);
    forall(range(nPrerequisites), i -> lessThan(s[prerequisites[i][0]],s[prerequisites[i][1]]))
      .note(”handling prerequisites”);
    minimize(MAXIMUM, cr)
      .note(”minimizing the maximum number of credits in periods”);
    decisionVariables(s);
  }
}

This model involves 4 arrays of variables and 4 types of constraints: extension, count, sum and intension (primitive lessThan). Actually, two series ’m1’ and ’m2’ of 12 instances each have been selected. The series ’m1’ corresponds to the model described above whereas ’m2’ (obtained after some reformulations) is compatible with the restrictions imposed for the mini-track. Decision variables are indicated, except for the instances (XCSP3 files) whose name contains ’nodv’ (no decision variables).

2.3 Bibd

This is Problem 028 on CSPLib, called Balanced Incomplete Block Designs (BIBD).

Description (from Steven Prestwich on CSPLib)

“BIBD generation is described in most standard textbooks on combinatorics. A BIBD is defined as an arrangement of distinct objects into blocks such that each block contains exactly distinct objects, each object occurs in exactly different blocks, and every two distinct objects occur together in exactly blocks. Another way of defining a BIBD is in terms of its incidence matrix, which is a by binary matrix with exactly ones per row, ones per column, and with a scalar product of between any pair of distinct rows. A BIBD is therefore specified by its parameters

Data

As an illustration of data specifying an instance of this problem, we have .

Model

The MCSP3 model used for the competition is:

class Bibd implements ProblemAPI {
  int v, b, r, k, lambda;
  public void model() {
    b = b != 0 ? b : (lambda * v * (v-1)) / (k * (k-1)); //when b is 0, we compute it
    r = r != 0 ? r : (lambda * (v-1)) / (k-1);           //when r is 0, we compute it
    Var[][] x = array(”x”, size(v, b), dom(0, 1),
      ”x[i][j] is the value at row i and column j of the matrix”);
    forall(range(v), i -> sum(x[i], EQ, r))
      .note(”constraints on rows”);
    forall(range(b), j -> sum(columnOf(x, j), EQ, k))
      .note(”constraints on columns”);
    forall(range(v), i -> forall(range(i + 1, v), j -> sum(x[i], weightedBy(x[j]), EQ, lambda)))
      .note(”scalar constraints with respect to lambda”);
    lexMatrix(x, INCREASING).tag(SYMMETRY_BREAKING);
      .note(”Increasingly ordering both rows and columns”)
  }
}

This model involves 1 array of variables and 2 types of constraints: sum and lexMatrix, the latter being used to break some variable symmetries. Two series ’sum’ and ’sc’ of 6 instances each have been selected. The series ’sum’ corresponds to the model variant described above whereas ’sc’ is a model variant obtained by introducing auxiliary variables.

2.4 Car Sequencing

This is Problem 001 on CSPLib.

Description (from Barbara Smith on CSPLib)

“A number of cars are to be produced; they are not identical, because different options are available as variants on the basic model. The assembly line has different stations which install the various options (air-conditioning, sun-roof, etc.). These stations have been designed to handle at most a certain percentage of the cars passing along the assembly line. Furthermore, the cars requiring a certain option must not be bunched together, otherwise the station will not be able to cope. Consequently, the cars must be arranged in a sequence so that the capacity of each station is never exceeded. For instance, if a particular station can only cope with at most half of the cars passing along the line, the sequence must be built so that at most 1 car in any 2 requires that option.”

Data

As an illustration of data specifying an instance of this problem, we have:

{
  "carClasses": [
    { "demand": 1, "options": [1, 0, 1, 1, 0] },
    { "demand": 1, "options": [0, 0, 0, 1, 0] },
    { "demand": 2, "options": [0, 1, 0, 0, 1] },
    { "demand": 2, "options": [0, 1, 0, 1, 0] },
    { "demand": 2, "options": [1, 0, 1, 0, 0] },
    { "demand": 2, "options": [1, 1, 0, 0, 0] }
  ],
  "optionLimits": [
    { "num": 1, "den": 2 },
    { "num": 2, "den": 3 },
    { "num": 1, "den": 3 },
    { "num": 2, "den": 5 },
    { "num": 1, "den": 5 }
  ]
}

Model

The MCSP3 model used for the competition is:

class CarSequencing implements ProblemAPI {
  CarClass[] classes;
  OptionLimit[] limits;
  class CarClass {
    int demand;
    int[] options;
  }
  class OptionLimit {
    int num;
    int den;
  }
  private Table channelingTable() {
    Table table = table();
    for (int i = 0; i < classes.length; i++)
      table.add(i, classes[i].options); //indexing car class options
    return table;
  }
  public void model() {
    int[] demands = valuesFrom(classes, cla -> cla.demand);
    int nCars = sumOf(demands), nOptions = limits.length, nClasses = classes.length;
    Range allClasses = range(nClasses);
    Var[] c = array(”c”, size(nCars), dom(allClasses)),
      ”c[i] is the class of the ith assembled car”);
    Var[][] o = array(”o”, size(nCars, nOptions), dom(0, 1),
      ”o[i][k] is 1 if the ith assembled car has option k”);
    cardinality(c, allClasses, occurExactly(demands))
      .note(”building the right numbers of cars per class”);
    forall(range(nCars), i -> extension(vars(c[i], o[i]), channelingTable()))
      .note(”linking cars and options”);
    forall(range(nOptions).range(nCars), (k, i) -> {
      if (i <= nCars - limits[k].den) {
        Var[] scp = select(columnOf(o, k), range(i, i + limits[k].den));
        sum(scp, LE, limits[k].num);
      }
    }).note(”constraints about option frequencies”);
    forall(range(nOptions).range(nCars), (k, i) -> {
      //i stands for the number of blocks set to the maximal capacity
      int nOptionOccurrences = sumOf(valuesFrom(classes, cla -> cla.options[k] * cla.demand));
      int nOptionsRemainingToSet = nOptionOccurrences - i * limits[k].num;
      int nOptionsPossibleToSet = nCars - i * limits[k].den;
      if (nOptionsRemainingToSet > 0 && nOptionsPossibleToSet > 0) {
        Var[] scp = select(columnOf(o, k), range(nOptionsPossibleToSet));
        sum(scp, GE, nOptionsRemainingToSet);
      }
    }).tag(REDUNDANT_CONSTRAINTS);
  }
}

This model involves 2 arrays of variables and 3 types of constraints: cardinality, extension and sum. Note that instead of posting extension constraints, we could have used binary intension constraints with a predicate like where is the value (0 or 1) of the kth option of the jth class. Also, note that we could have used a cache for the table built by matchs(). The last group of constraints corresponds to redundant constraints. A series of 17 instances has been selected for the competition.

2.5 Coloured Queens

Description

The queens graph is a graph with n*n nodes corresponding to the squares of a chess-board. There is an edge between nodes iff they are on the same row, column, or diagonal, i.e., if two queens on those squares would attack each other. The coloring problem is to color the queens graph with colors. See [13].

Data

As an illustration of data specifying an instance of this problem, we simply have .

Model

The MCSP3 model used for the competition is:

class ColouredQueens implements ProblemAPI {
  int n;
  public void model() {
    Var[][] x = array(”x”, size(n, n), dom(range(n)),
      ”x[i][j] is the color at row i and column j”);
    Var[][] dn = diagonalsDown(x), up = diagonalsUp(x); //precomputing scopes
    allDifferentMatrix(x)
      .note(”different colors on rows and columns”);
    forall(range(dn.length), i -> allDifferent(dn[i])
      .note(”different colors on downward diagonals”));
    forall(range(up.length), i -> allDifferent(up[i])
      .note(”different colors on upward diagonals”));
  }
}

This model only involves 1 array of variables and 2 types of constraints: allDifferent and allDifferentMatrix. A series of 12 instances has been selected for the competition.

2.6 Crosswords (Satisfaction)

This problem has already been used in previous XCSP competitions, because it notably permits to compare filtering algorithms on large table constraints.

Description

“Given a grid with imposed black cells (spots) and a dictionary, the problem is to fulfill the grid with the words contained in the dictionary.”

Data

As an illustration of data specifying an instance of this problem, we have:

{
  "spots": [[0,1,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,1]],
  "dictFileName": "ogd"
}

Model

The MCSP3 model used for the competition is:

class Crossword implements ProblemAPI {
  int[][] spots;
  String dictFileName;
  private Map<Integer, List<int[]>> loadWords() {
    Map<Integer, List<int[]>> words = new HashMap<>();
    readFileLines(dictFileName).forEach(w ->
      words.computeIfAbsent(w.length(), k -> new ArrayList<>()).add(Utilities.wordAsIntArray(w))
    );
    return words;
  }
  private class Hole {
    int row, col, size;
    boolean horizontal;
    Hole(int row, int col, int size, boolean horizontal) {
      this.row = horizontal ? row : col;
      this.col = horizontal ? col : row;
      this.size = size;
      this.horizontal = horizontal;
    }
    Var[] scope(Var[][] x) {
      return variablesFrom(range(size), i -> horizontal ? x[row][col + i] : x[row + i][col]);
    }
  }
  private List<Hole> findHoles(int[][] t, boolean untransposed) {
    int nRows = t.length, nCols = t[0].length;
    List<Hole> list = new ArrayList<>();
    for (int i = 0; i < nRows; i++) {
      int start = -1;
      for (int j = 0; j < nCols; j++)
        if (t[i][j] == 1) { //if spot (black cell)
          if (start != -1 && j - start >= 2)
            list.add(new Hole(i, start, j - start, untransposed));
          start = -1;
        } else {
          if (start == -1)
            start = j;
          else if (j == nCols - 1 && nCols - start >= 2)
            list.add(new Hole(i, start, nCols - start, untransposed));
        }
    }
    return list;
  }
  private Hole[] findHoles() {
    List<Hole> list = findHoles(spots, true);
    list.addAll(findHoles(transpose(spots), false));
    return list.toArray(new Hole[0]);
  }
  public void model() {
    Map<Integer, List<int[]>> words = loadWords();
    Hole[] holes = findHoles();
    int nRows = spots.length, nCols = spots[0].length, nHoles = holes.length;
    Var[][] x = array(”x”, size(nRows, nCols), (i, j) -> dom(range(26)).when(spots[i][j] == 0),
      ”x[i][j] is the letter, number from 0 to 25, at row i and column j (when no spot)”);
    forall(range(nHoles), i -> extension(holes[i].scope(x), words.get(holes[i].size)))
      .note(”fill the grid with words”);
  }
}

This satisfaction problem only involves 1 array of variables and 1 type of constraints: extension (ordinary table constraints). For clarity, we use an auxiliary class Hole. A series of 13 instances, with only blank grids, has been selected for the competition.

2.7 Crosswords (Optimization)

This problem is the subject of a regular Romanian challenge, and has been studied in XX.

Description

“Given a main dictionary containing ordinary words, and a second dictionary containing thematic words, the objective is to fill up a grid with words of both dictionary. Each word from the thematic word has a value (benefit) equal to its length. The objective is to maximize the overall value. The problem is difficult because black cells are not imposed, i.e., can be put anywhere in the grid (but no adjacency of black cells is authorized).”

Data

As an illustration of data specifying an instance of this problem, we have:

{
  "n": 10,
  "nMaxWords": 5,
  "mainDict": "mainDictRomanian.txt",
  "thematicDict": "thematicDictRomanian2017.txt"
}

Model

The MCSP3 model used for the competition is:

class CrosswordDesign implements ProblemAPI {
  int n; //size of the grid (number of rows and number of columns)
  int nMaxWords; //maximum number of words that can be put on a same row or column
  String mainDict, thematicDict;
  @NotData
  String[] words; //words of the two merged dictionaries
  @NotData
  int[] wordsPoints; //value of each word
  private void loadWords() {
    words = Stream.concat(readFileLines(mainDict), readFileLines(thematicDict))).toArray(String[]::new);
    wordsPoints = new int[words.length];
    List<String> list = Arrays.asList(words);
    readFileLines(thematicDict).forEach(w -> {
      int pos = list.indexOf(w);
      if (pos != -1)
        wordsPoints[pos] = w.length(); //thematic words have some value (their lengths)
    });
  }
  private Table shortTable(int k) {
    boolean lastWord = k == nMaxWords - 1;
    List<int[]> list = new ArrayList<>();
    if (k != 0)
      list.add(range(n + 4).map(i -> i == 0 || i == 1 | i == 3 ? -1 : i == 2 ? 0 : STAR));
    int[] possiblePositions = k == 0 ? vals(0, 1) : vals(range(2 * k, n));
    for (int p : possiblePositions)
      for (int i = 0; i < words.length; i++) {
        int bp = p + words[i].length(); //position of the black point, just after the word
        if (bp <= n) {
          int[] tuple = new int[n + 4];
          tuple[0] = p;
          tuple[1] = i;
          tuple[2] = wordsPoints[i];
          if (lastWord && bp < n - 1)
            continue;
          tuple[3] = lastWord ? -1 : bp <= n - 2 ? bp + 1 : -1;
          for (int j = 4; j < tuple.length; j++) {
            if (j - 4 == p - 1 || j - 4 == bp)
              tuple[j] = 26; //black points
            else if (p <= j - 4 && j - 4 < p + words[i].length())
              tuple[j] = words[i].charAt(j - 4 - p) - 97;
            else
              tuple[j] = STAR;
          }
          list.add(tuple);
        }
      }
    return table().add(list);
  }
  private int[] positionValues(int k) {
    return k == 0 ? vals(0, 1) : k == nMaxWords ? vals(-1) : vals(range(-1, n));
  }
  public void model() {
    loadWords();
    int nWords = words.length;
    Var[][] x = array(”x”, size(n, n), dom(range(27)),
      ”x[i][j] is the (number for) letter at row i and col j; 26 stands for a black point”);
    Var[][] r = array(”r”, size(n, nMaxWords), dom(range(-1, nWords)),
      ”r[i][k] is the (index of) kth word at row i; -1 means no word”);
    Var[][] c = array(”c”, size(n, nMaxWords), dom(range(-1, nWords)),
      ”c[j][k] is the (index of) kth word at col j; -1 means no word”);
    Var[][] pr = array(”pr”, size(n, nMaxWords + 1), (i, k) -> dom(positionValues(k)),
      ”pr[i][k] is the position (index of col) of the kth word at row i; -1 means no word”);
    Var[][] pc = array(”pc”, size(n, nMaxWords + 1), (j, k) -> dom(positionValues(k)),
      ”pc[j][k] is the position (index of row) of the kth word at col j; -1 means no word”);
    Var[][] br = array(”br”, size(n, nMaxWords), dom(range(n + 1)),
      ”br[i][k] is the benefit of the kth word at row i”);
    Var[][] bc = array(”bc”, size(n, nMaxWords), dom(range(n + 1)),
      ”bc[j][k] is the benefit of the kth word at col j”);
    forall(range(n).range(nMaxWords), (i, k) ->
      extension(vars(pr[i][k], r[i][k], br[i][k], pr[i][k+1], x[i]), shortTable(k)))
    .note(”putting words on rows”);
    forall(range(n).range(nMaxWords), (j, k) ->
      extension(vars(pc[j][k], c[j][k], bc[j][k], pc[j][k+1], columnOf(x, j)), shortTable(k)))
    .note(”putting words on columns”);
      maximize(SUM, vars(br, bc))
        .note(”maximizing the summed benefit of words put in the grid”);
  }
}

This optimization problem involves 7 arrays of variables and simply the constraint extension. However, do note that such constraints are built with large short tables (i.e., tables involving ’*’, denoted by STAR in the code). The auxiliary methods loadWords() and shortTable() are respectively useful for loading the dictionaries and computing the short tables. A series of 13 instances has been selected for the competition.

2.8 Dubois

This problem has been conceived by Olivier Dubois, and submitted to the second DIMACS Implementation Challenge. Dubois’s generator produces contradictory 3-SAT instances that seem very difficult to be solved by any general method.

Description

“Given an integer , called the degree, Dubois’s process allows us to construct a 3-SAT contradictory instance with variables and clauses, each of them having 3 literals.”

Data

As an illustration of data specifying an instance of this problem, we simply have .

Model

The MCSP3 model used for the competition is:

class Dubois implements ProblemAPI {
  int n;
  public void model() {
    Table table1 = table(”(0,0,1)(0,1,0)(1,0,0)(1,1,1)”), table2 = table(”(0,0,0)(0,1,1)(1,0,1)(1,1,0)”);
    Var[] x = array(”x”, size(3 * n), dom(0, 1))
      .note(”x[i] is the Boolean value (0/1) of the ith variable of Dubois's sequence”);
    extension(vars(x[2*n - 2], x[2*n - 1], x[0]), table1);
    forall(range(n - 2), i -> extension(vars(x[i], x[2*n + i], x[i + 1]), table1));
    forall(range(2), i -> extension(vars(x[n - 2 + i], x[3*n - 2], x[3 * n - 1]), table1));
    forall(range(n, 2*n - 2), i -> extension(vars(x[i], x[4*n - 3 - i], x[i - 1]), table1));
    extension(vars(x[2 * n - 2], x[2 * n - 1], x[2 * n - 3]), table2);
  }
}

This model involves 1 array of variables and 1 type of constraints: extension. A series of 12 instances has been selected for the competition.

2.9 Eternity

Eternity II is a famous edge-matching puzzle, released in July 2007 by TOMY, with a 2 million dollars prize for the first submitted solution. See, for example, [2]. Here, we are interested in instances derived from the original problem by the BeCool team of the UCL (“Université Catholique de Louvain”) who proposed them for the competition.

Description

“On a board of size , you have to put square tiles (pieces) that are described by four colors (one for each direction : top, right, bottom and left). All adjacent tiles on the board must have matching colors along their common edge. All edges must have color ’0’ on the border of the board.”

Data

As an illustration of data specifying an instance of this problem, we have:

{
  "n": 3,
  "m": 3,
  "pieces": [[0,0,1,1], [0,0,1,2], [0,0,2,1], [0,0,2,2], [0,1,3,2], [0,1,4,1], [0,2,3,1], [0,2,4,2], [3,3,4,4]]
}

Model

The MCSP3 model used for the competition is:

class Eternity implements ProblemAPI {
  int n, m;
  int[][] pieces;
  private Table piecesTable() {
    Table table = table();
    for (int i = 0; i < n * m; i++)
      for (int r = 0; r < 4; r++) //handling rotation
        table.add(i, pieces[i][r % 4], pieces[i][(r+1) %4 ], pieces[i][(r+2) % 4], pieces[i][(r+3) % 4]);
    return table;
  }
  public void model() {
    int maxValue = maxOf(valuesIn(pieces)); //max possible value on pieces
    Var[][] id = array(”id”, size(n, m), dom(range(n * m)),
      ”id[i][j] is the id of the piece at row i and column j”);
    Var[][] top = array(”top”, size(n, m), dom(range(0, maxValue)),
      ”top[i][j] is the value at the top of the piece put at row i and column j”);
    Var[][] left = array(”left”, size(n, m), dom(range(0, maxValue)),
      ”left[i][j] is the value at the left of the piece put at row i and column j”);
    Var[] bot = array(”bot”, size(m), dom(range(0, maxValue)),
      ”bot[j] is the value at the bottom of the piece put at the bottommost row and column j”);
    Var[] right = array(”right”, size(n), dom(range(0, maxValue)),
      ”right[i] is the value at the right of the piece put at the row i and the rightmost column”);
    allDifferent(id)
      .note(”all pieces must be placed (only once)”);
    forall(range(n).range(m), (i, j) -> {
      Var lr = j < m - 1 ? left[i][j + 1] : right[j], tb = i < n - 1 ? top[i + 1][j] : bot[j];
      extension(vars(id[i][j], top[i][j], lr, tb, left[i][j]), piecesTable());
    }).note(”pieces must be valid (i.e. correspond to those given initially, possibly after rotation)”);
    block(() -> {
      forall(range(n), i -> equal(left[i][0], 0));
      forall(range(n), i -> equal(right[i], 0));
      forall(range(m), j -> equal(top[0][j], 0));
      forall(range(m), j -> equal(bot[j], 0));
    }).note(”put special value 0 on borders”);
  }
}

This model involves 5 arrays of variables and 3 types of constraints: allDifferent, extension and intension (primitive equal). Note that we could have stored and reused the table, instead of creating it systematically. A series of 15 instances has been selected for the competition.

2.10 Fapp

The frequency assignment problem with polarization constraints (FAPP) is an optimization problem111This is an extended subject of the CALMA European project that was part of the ROADEF’2001 challenge222See http://uma.ensta.fr/conf/roadef-2001-challenge/. In this problem, there are constraints concerning frequencies and polarizations of radio links. Progressive relaxation of these constraints is explored: the relaxation level is between 0 (no relaxation) and 10 (the maximum relaxation). Whereas we used simplified CSP instances of this problem in previous XCSP competitions, do note here that we have considered the original COP instances.

Description

The description is rather complex. Hence, we refer the reader to:
https://uma.ensta-paristech.fr/conf/roadef-2001-challenge/distrib/fapp_roadef01_rev2_tex.pdf

Data

As an illustration of data specifying an instance of this problem, we have:

{
  "domains": {
    "0": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
    "1": [25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
    "2": [55, 56, 57, 63, 64, 65]},
  "routes": [
    { "domain": 1, "polarization": -1 },
    { "domain": 1, "polarization": 0 },
    ...
  ],
  "hards": [
    { "route1": 1, "route2": 2, "frequency": true, "equality": true, "gap": 36 },
    { "route1": 0, "route2": 1, "frequency": true, "equality": true, "gap": 0 },
    ...
  ],
  "softs": [
    { "route1": 0, "route2": 2, "eqRelaxations": [46,44,42,42,40,40,35,35,35,30,20],
      "neRelaxations": [39,37,35,35,33,33,28,28,28,23,13] },
    { "route1": 0, "route2": 8, "eqRelaxations": [30,29,28,27,26,25,24,23,22,21,20],
      "neRelaxations": [29,28,27,26,25,24,23,22,21,20,19] },
    { "route1": 1, "route2": 3, "eqRelaxations": [33,32,30,30,29,28,27,22,17,12,7],
      "neRelaxations": [29,28,27,27,27,26,25,20,15,10,5] },
    ...
  ]
}

Model

The MCSP3 model used for the competition is:

class Fapp implements ProblemAPI {
  Map<Integer, int[]> domains;
  Route[] routes;
  HardCtr[] hards;
  SoftCtr[] softs;
  class Route {
    int domain, polarization;
    int[] polarizationValues() {
      return polarization == 0 ? vals(0, 1) : polarization == 1 ? vals(1) : vals(0);
    }
  }
  class HardCtr {
    int route1, route2;
    boolean frequency, equality;
    int gap;
  }
  class SoftCtr {
    int route1, route2;
    int[] eqRelaxations;
    int[] neRelaxations;
  }
  private boolean softLink(int i, int j) {
    return firstFrom(softs, c -> c.route1 == i && c.route2 == j || c.route1 == j && c.route2 ==i) != null;
  }
  private int[] distances(int i, int j) {
    int[] dom1 = domains.get(routes[i].domain), dom2 = domains.get(routes[j].domain);
    return IntStream.of(dom1).flatMap(f1 -> IntStream.of(dom2).map(f2 -> Math.abs(f1 - f2))).toArray();
  }
  private CtrEntity imperativeConstraint(Var[] f, Var[] p, HardCtr c) {
    int i = c.route1, j = c.route2;
    if (c.frequency) {
      if (c.gap == 0)
        return c.equality ? equal(f[i], f[j]) : different(f[i], f[j]);
      else
        return c.equality ? equal(dist(f[i], f[j]), c.gap) : different(dist(f[i], f[j]), c.gap);
    }
    return c.equality ? equal(p[i], p[j]) : different(p[i], p[j]);
  }
  private Table relaxTable(SoftCtr c) {
    Table table = table();
    Set<Integer> set = new HashSet<>();
    int i = c.route1, j = c.route2;
    for (int fi : domains.get(routes[i].domain))
      for (int fj : domains.get(routes[j].domain)) {
        int dist = Math.abs(fi - fj);
        if (set.contains(dist))
          continue; //because already encountered
        for (int pol = 0; pol < 4; pol++) {
          int pi = pol < 2 ? 0 : 1;
          int pj = pol == 1 || pol == 3 ? 1 : 0;
          if (routes[i].polarization == 1 && pi == 0 || routes[j].polarization == 1 && pj == 0)
            continue;
          if (routes[i].polarization == -1 && pi == 1 || routes[j].polarization == -1 && pj == 1)
            continue;
          int[] t = pi == pj ? c.eqRelaxations : c.neRelaxations;
          for (int k = 0; k <= 11; k++) {
            if (k == 11 || dist >= t[k]) { //for k=11, we suppose t[k] = 0
              int sum = IntStream.range(0, k - 1).map(l -> dist >= t[l] ? 0 : 1).sum();
              table.add(dist, pi, pj, k, k == 0 || dist >= t[k - 1] ? 0 : 1, k <= 1 ? 0 : sum);
            }
          }
        }
        set.add(dist);
      }
    return table;
  }
 public void model() {
   int n = routes.length, nHards = hards == null ? 0 : hards.length, nSofts = softs.length;
   Var[] f = array(”f”, size(n), i -> dom(domains.get(routes[i].domain)),
     ”f[i] is the frequency of the ith radio-link”);
   Var[] p = array(”p”, size(n), i -> dom(routes[i].polarizationValues())),
     ”p[i] is the polarization of the ith radio-link”);
   Var[][] d = array(”d”, size(n, n), (i, j) -> dom(distances(i, j)).when(i < j && softLink(i,j)),
     ”d[i][j] is the distance between the ith and the jth frequencies, for i < j when a soft link exists”);
   Var[] v1 = array(”v1”, size(nSofts), dom(0, 1),
     ”v1[q] is 1 iff the qth pair of radio constraints is violated when relaxing another level”);
   Var[] v2 = array(”v2”, size(nSofts), dom(range(11)),
     ”v2[q] is the number of times the qth pair of radio constraints is violated when relaxing more than one level”);
   Var k = var(”k”, dom(range(12)),
     ”k is the relaxation level to be optimized”);
   forall(range(n).range(n), (i, j) -> {
     if (i < j && softLink(i,j))
       equal(d[i][j], dist(f[i], f[j]));
   }).note(”computing intermediary distances”);
   forall(range(nHards), q -> imperativeConstraint(f, p, hards[q])))
     .note(”imperative constraints”);
   forall(range(nSofts), q -> {
     int i = softs[q].route1, j = softs[q].route2;
     extension(vars(i < j ? d[i][j] : d[j][i], p[i], p[j], k, v1[q], v2[q]), relaxTable(softs[q]));
   }).note(”relaxable radioelectric compatibility constraints”);
   int[] coeffs = vals(10 * nSofts * nSofts, repeat(10 * nSofts, nSofts), repeat(1, nSofts));
   minimize(SUM, vars(k, v1, v2), weightedBy(coeffs))
     .note(”minimizing sophisticated relaxation cost”);
 }
}

This model involves 5 arrays of variables (as well as the stand-alone variable ) and two types of constraints: extension and intension. A cache could be used for avoiding creating similar tables, and also for avoiding checking several times whether a given pair ) is subject to a soft link. Two series ’m2s’ and ’ext’ of respectively 18 and 10 instances have been selected. The series ’m2s’ corresponds to the model described above whereas the series ’ext’ (obtained after some reformulations) is compatible with the restrictions imposed for the mini-track.

2.11 Frb

This problem has been already used in previous XCSP competitions. Hence, we very succinctly introduce it.

Description

These instances are randomly generated using Model RB [23], while guaranteeing satisfiability.

This satisfaction problem only involves (ordinary) table constraints. A series of 16 instances has been selected. Using model RB, some forced binary CSP instances have been generated by choosing , , and varying from to . Each such instance is prefixed by frb-n.

2.12 Golomb Ruler

This is Problem 006 on CSPLib, called Golomb Ruler.

Description (from Peter van Beek on CSPLib)

“The problem is to find the ruler with the smallest length where we can put marks such that the distance between any two pairs of marks is distinct.”

Data

As an illustration of data specifying an instance of this problem, we simply have .

Model

The MCSP3 model used for the competition is:

class GolombRuler implements ProblemAPI {
  int n;
  public void model() {
    int rulerLength = n * n + 1; //a trivial upper-bound
    Var[] x = array(”x”, size(n), dom(range(rulerLength)),
      ”x[i] is the position of the ith tick”);
    Var[][] y = array(”y”, size(n, n), (i, j) -> dom(range(1, rulerLength)).when(i < j),
      ”y[i][j] is the distance between x[i] and x[j], for i < j”);
    allDifferent(y)
      .note(”all distances are different”);
    forall(range(n), i -> forall(range(i + 1, n), j -> equal(x[j], add(x[i], y[i][j]))))
      .note(”computing distances”);
    minimize(x[n - 1])
      .note(”minimizing the position of the rightmost tick”);
    decisionVariables(x);
  }
}

This model involves 2 arrays of variables and 2 types of constraints: allDifferent and intension (equal). A series of instances has been chosen ( varying from 7 to 16). Decision variables are indicated, except for the 3 instances (XCSP3 files) whose name contains ’nodv’ (no decision variables).

2.13 Graceful Graph

This is Problem 053 on CSPLib, called Graceful Graph. See, for example, [21].

Description (from Karen Petrie on CSPLib)

“A labelling of the nodes of a graph with edges is graceful if assigns each node a unique label from and when each edge is labelled with , the edge labels are all different. (Hence, the edge labels are a permutation of .)”

We focused on graphs of the form that consist of copies of a clique K of size with corresponding nodes of the cliques also forming the nodes of a path of length .

Data

As an illustration of data specifying an instance of this problem, we have .

Model

The MCSP3 model used for the competition is:

class GracefulGraph implements ProblemAPI {
  int k; //size of each clique K (number of nodes)
  int p; //size of each path P (or equivalently, number of cliques)
  public void model() {
    int nEdges = ((k * (k - 1)) * p) / 2 + k * (p - 1);
    Var[][] cn = array(”cn”, size(p, k), dom(range(nEdges + 1)),
      ”cn[i][j] is the color of the jth node of the ith clique”);
    Var[][][] ce = array(”ce”, size(p, k, k), (i, j1, j2) -> dom(range(1, nEdges + 1)).when(j1 < j2),
      ”ce[i][j1][j2] is the color of the edge (j1, j2) of the ith clique, for j1 < j2”);
    Var[][] cp = array(”cp”, size(p - 1, k), dom(range(1, nEdges + 1)),
      ”cp[i][j] is the color of the jth edge of the ith path”);
    allDifferent(cn)
      .note(”all nodes are colored differently”);
    allDifferent(vars(ce, cp))
      .note(”all edges are colored differently”);
    block(() -> {
      forall(range(p).range(k), (i, j1) -> forall(range(j1 + 1, k), j2 ->
        equal(ce[i][j1][j2], dist(cn[i][j1], cn[i][j2]))));
      forall(range(p - 1).range(k), (i, j) -> equal(cp[i][j], dist(cn[i][j], cn[i + 1][j])));
    }).note(”computing colors of edges from colors of nodes”);
  }
}

This model involves 3 arrays of variables and 2 types of constraints: allDifferent and intension (equal). A series of 11 instances has been selected.

2.14 Graph Coloring

This well-known problem has been already used in previous XCSP competitions.

Description

“Given a graph , the objective is to find the minimum number of colors such that it is possible to color each node of while ensuring that no two adjacent nodes share the same color.”

Model

The MCSP3 model used for the competition is:

class Coloring implements ProblemAPI {
  int nNodes, nColors;
  int[][] edges;
  public void model() {
    int nEdges = edges.length;
    Var[] x = array(”x”, size(nNodes), dom(range(nColors)),
      ”x[i] is the color assigned to the ith node of the graph”);
    forall(range(nEdges), i -> different(x[edges[i][0]], x[edges[i][1]]))
      .note(”all adjacent nodes must be colored differently”);
    minimize(MAXIMUM, x)
      .note(”minimizing the maximum used color index (and, consequently, the number of colors)”);
  }
}

This model only involves 1 array of variables and 1 type of constraint: intension (different). A series of 11 instances has been selected for the competition.

2.15 Haystacks

This problem, introduced by Marc Van Dongen, has been already used in previous XCSP competitions.

Description (from Marc Van Dongen)

“The problem instance of order has variables with domain . The constraint graph is highly regular, consisting of clusters: one central cluster and outer clusters, each one being a -clique. The instances are designed so that if the variables in the central cluster are instantiated, only one of the outer clusters contains an inconsistency: this cluster is the haystack. The task is to find the haystack and decide that it is unsatisfiable, thereby providing a proof that the current instantiation of the variables in the central cluster is inconsistent.”

A series of 10 instances has been selected for the competition.

2.16 Knapsack

This is Problem 133 on CSPLib, called Knapsack.

Description

“Given a set of items, each with a weight and a value, determine which items to include in a collection so that the total weight is less than or equal to a given capacity and the total value is as large as possible.”

Data

As an illustration of data specifying an instance of this problem, we have:

{
  "capacity": 10,
  "items": [
    { "weight": 2, "value": 54 },
    { "weight": 2, "value": 92 },
    { "weight": 1, "value": 62 },
    { "weight": 2,"value": 20 },
    { "weight": 2,"value": 55 }
  ]
}

Model

The MCSP3 model used for the competition is:

class Knapsack implements ProblemAPI {
  int capacity;
  Item[] items;
  class Item {
    int weight;
    int value;
  }
  public void model() {
    int[] weights = valuesFrom(items, item -> item.weight);
    int[] values = valuesFrom(items, item -> item.value);
    int nItems = items.length;
    Var[] x = array(”x”, size(nItems), dom(0, 1),
      ”x[i] is 1 iff the ith item is selected”);
    sum(x, weightedBy(weights), LE, capacity)
      .note(”the capacity of the knapsack must not be exceeded”);
    maximize(SUM, x, weightedBy(values))
      .note(”maximizing summed up value (benefit)”);
  }
}

This model only involves 1 array of variables and 1 type of constraint: sum. A series of 14 instances has been selected for the competition.

2.17 Langford

This is Problem 024 on CSPLib, called Langdford’s number problem.

Description (from Toby Walsh on CSPLib)

“Given two integers and , the problem is to arrange sets of numbers to , so that each appearance of the number is numbers on from the last.”

Data

Here, we focus on the model proposed in [10] for . The MCSP3 model used for the competition is:

class LangfordBin implements ProblemAPI {
  int n;
  public void model() {
    Var[] v = array(”v”, size(2 * n), dom(range(1, n + 1)),
      ”v[i] is the ith value of the Langford vector);
    Var[] p = array(”p”, size(2 * n), dom(range(2 * n)),
      ”p[j] is the first (resp., second) position of 1+j/2 in v if j is even (resp., odd)”);
    forall(range(n), i -> element(v, at(p[2 * i]), takingValue(i + 1)))
      .note(”computing the position of the 1st occurrence of i”);
    forall(range(n), i -> element(v, at(p[2 * i + 1]), takingValue(i + 1)))
      .note(”computing the position of the 2nd occurrence of i”);
    forall(range(n), i -> equal(p[2 * i], add(i + 2, p[2 * i + 1])))
      .note(”the distance between two occurrences of i must be respected”);
  }
}

This model involves 2 arrays of variables and 2 types of constraints: element and intension (equal). A series of 11 instances has been generated for the competition, by varying from 6 to 16.

2.18 Low Autocorrelation

This is Problem 005 on CSPLib, called Low Autocorrelation Binary Sequences.

Description (from Toby Walsh on CSPLib)

“The objective is to construct a binary sequence of length that minimizes the autocorrelations between bits. Each bit in the sequence takes the value or . With non-periodic (or open) boundary conditions, the kth autocorrelation, is defined to be . The aim is to minimize the sum of the squares of these autocorrelations, i.e., to minimize .

Data

As an illustration of data specifying an instance of this problem, we have .

Model

The MCSP3 model used for the competition is:

class LowAutocorrelation implements ProblemAPI {
  int n;
  public void model() {
    Var[] x = array(”x”, size(n), dom(-1, 1),
      ”x[i] is the ith value of the sequence to be built.”);
    Var[][] y = array(”y”, size(n - 1, n - 1), (k, i) -> dom(-1, 1).when(i < n - k - 1),
      ”y[k][i] is the ith product value required to compute the kth autocorrelation”);
    Var[] c = array(”c”, size(n - 1), k -> dom(range(-n + k + 1, n - k)),
      ”c[k] is the value of the kth autocorrelation”);
    Var[] s = array(”s”, size(n - 1), k -> dom(range(n - k).map(v -> v * v)),
      ”s[k] is the square of the kth autocorrelation”);
    forall(range(n - 1), k -> forall(range(n - k - 1), i -> equal(y[k][i], mul(x[i], x[i + k + 1]))))
      .note(”computing product values”);
    forall(range(n - 1), k -> sum(y[k], EQ, c[k]))
      .note(”computing the values of the autocorrelations”);
    forall(range(n - 1), k -> equal(s[k], mul(c[k], c[k])))
      .note(”computing the squares of the autocorrelations”);
    minimize(SUM, s)
      .note(”minimizing the sum of the squares of the autocorrelation”);
  }
}

This model involves 4 arrays of variables and 2 types of constraints: sum and intension (equal). A series of 14 instances has been generated for the competition.

2.19 Magic Hexagon

This is Problem 023 on CSPLib, called Magic Hexagon.

Description

“A magic hexagon consists of the numbers 1 to 19 arranged in a hexagonal pattern such that all diagonals sum to 38.”

The description is given here for order (the length of the first row of the hexagon) and starting value (the first value of the sequence of numbers).

Model

The MCSP3 model used for the competition is:

class MagicHexagon implements ProblemAPI {
  int n; //order
  int s; //start
  private Var[] scopeForDiagonal(Var[][] x, int i, boolean right) {
    int d = x.length;
    int v1 = right ? Math.max(0, d / 2 - i) : Math.max(0, i - d / 2), v2 = d / 2 - v1;
    Range r = range(d - Math.abs(d / 2 - i));
    return variablesFrom(r, j -> x[j + v1][i - Math.max(0, right ? v2 - j : j - v2)]);
  }
  public void model() {
    int gap = 3 * n * n - 3 * n + 1;
    int magic = sumOf(range(s, s + gap)) / (2 * n - 1);
    int