" /> My Constraint Programming Blog: July 2010 Archives

« June 2010 | Main | August 2010 »

July 28, 2010

Jacob Feldman has started to blog about constraint programming standardization

Jacob Feldman has started to blog about constraint programming standardization: Constraint Programming Standardization Blog. In the first larger post Road to CP Standardization he explains the purpose of the blog, and the road to constraint programming standardization.

For more information, see Standardization of Constraint Programming (www.cpstandards.org/), its forum, and the JSR 331: Constraint Programming API.

Also see Open Rules, and do as I do: follow Jacob on Twitter: Jacob_OpenRules.

July 26, 2010

About 100 new Gecode models

Quite a few new Gecode models has been written to experiment with the new syntax sugar in Gecode version 3.4. Many of the models are Gecode versions of the models presented in Some 40 new ECLiPSe models, where almost all of these where first done in MiniZinc and then SICStus Prolog before implementing in ECLiPSe. So, now it's time for Gecode versions. It is probably not very surprising that it is much easier to translate from the MiniZinc version to Gecode than from the two Prolog-based versions. I have implemented all but 2 of these "about 40" ECLiPSe models.

As I wrote in ..., the new syntactic sugar for rel and expr (substituting the post in older Gecode versions) is very nice and it now much easier to write many constraints. As you may see in the examples, I also tend to (over)use the new append operator for IntVarArgs; it is very handy sometimes, e.g. when you don't know - or don't care to calculate - the length of an array with "dynamically" created IntVar's.

New Gecode models

Here are all the new models, often with comments about the problem or how I implemented them. Almost all of them has also been implemented in some - or all - of these systems:

Optimizing shopping basket

This is a rather straightforward translation of the MiniZinc model shopping_basket6.mzn where described in Optimizing shopping baskets: The development of a MiniZinc model and was presented in the StackOverflow question How to use constraint programming for optimizing shopping baskets?. The object is to minimize the cost of a shopping basket where items are from different shops, and there is a delivery cost ("punishment") if the total from a shop is below a certain limit.

Some comments:

1) Calculating the delivery_cost "punishment"
For calculating the delivery cost for a shop, first a total for the shop is summed. Here we loop over all shops and all items, and the shop's item cost is added if the item is bought from this shop (or else the cost for the item is 0). The implication (>>) is used. Here is my first attempt, i.e. to explicit state the two different cases:
rel(*this, (x[item] == shop) >> (this_shop_cost[item] == costs_m(shop,item)));
rel(*this, (x[item] != shop) >> (this_shop_cost[item] == 0));
However, there is a better way to state this constraint, better both in terms of modeling and propagation:
rel(*this, 
   this_shop_cost[item] == 
   expr(*this, x[item] == shop)*costs_m(shop,item));
Then, given the total cost for this shop, we see if there is a delivery cost. Again, the implication is used. Note the combined condition that cost must be larger than 0 in order for checking the delivery cost. Here is the first (very explicit) try:
// the cost is larger than 0 but below the limit
rel(*this, 
   (shop_costs[shop] > 0 && shop_costs[shop] <= delivery_costs_limits[shop]) 
   >>
   (punish[shop] == delivery_costs[shop]));
// no punishment: either 0 or larger than the limit
rel(*this, 
   (shop_costs[shop] == 0 ||  shop_costs[shop] > delivery_costs_limits[shop]) 
   >>
  (punish[shop] == 0));
Again, a better solution was found (or crafted):
rel(*this, 
punish[shop]==
  expr(*this,
       (shop_costs[shop] > 0 && 
        shop_costs[shop] <= delivery_costs_limits[shop])
      )*delivery_costs[shop]);
Probably this is slightly too influenced by MiniZinc's high-level syntax:
punish[j] = 
    delivery_costs[j]*bool2int(this_cost > 0 /\ 
            this_cost < delivery_costs_limits[j])
Using the first two attempts cited above, the model first had 30031 failures (and about 11 seconds). With the two improvements the failures decreased to 5012 failures (and about 2 seconds).

The solution is - of course - the same as for the MiniZinc model.

There are two solutions with a minimal total of 42013. To show these two, use the following command line options
  shopping_basket6 -search dfs 42013
The result is below. Note that the the first shops is named 0 in the x array, whereas in the MiniZinc model it is named 1.
total: 42013
x: {12, 19, 16, 17, 17, 12, 16, 16, 19, 12, 16, 16, 12, 12, 17, 16, 12, 12, 16, 7, 12, 35, 9, 16, 12, 12, 16, 19, 12}
item_costs: {345, 2921, 3074, 1233, 2554, 878, 1715, 3202, 2335, 639, 1644, 1606, 730, 1096, 1132, 1176, 1654, 1908, 2277, 298, 503, 927, 2182, 449, 397, 1246, 2145, 799, 558}
shop_costs: {0, 0, 0, 0, 0, 0, 0, 298, 0, 2182, 0, 0, 9954, 0, 0, 0, 17288, 4919, 0, 6055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 927, 0}
punish: {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 390, 0}

total: 42013
x: {12, 19, 16, 17, 17, 12, 16, 16, 19, 12, 16, 12, 12, 12, 17, 16, 12, 12, 16, 7, 12, 35, 9, 16, 12, 12, 16, 19, 12}
item_costs: {345, 2921, 3074, 1233, 2554, 878, 1715, 3202, 2335, 639, 1644, 1606, 730, 1096, 1132, 1176, 1654, 1908, 2277, 298, 503, 927, 2182, 449, 397, 1246, 2145, 799, 558}
shop_costs: {0, 0, 0, 0, 0, 0, 0, 298, 0, 2182, 0, 0, 11560, 0, 0, 0, 15682, 4919, 0, 6055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 927, 0}
punish: {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 390, 0}
When developing this Gecode model, I wanted to see all the intermediate results, i.e. the item costs, which shop had delivery costs (punish), etc, and then I kept them in the final model.

Costas Array

Model: costas_array.cpp

Generating Costas Arrays (MathWorld, see also Wikipedia's entry), has been a quite popular example in constraint programming. So here is my take.

This model is a port of my MiniZinc model costas_array.mzn (which in its turn is based on Barry O'Sullivan's MiniZinc model CostasArray.mzn). Two comments:
  • Note that the matrix, here defined by
    Matrix<IntVarArray> diffs(differences, n, n);
    
    is accessed diffs(column, row). I tend to forget this.
  • Upper triangular matrix
    The Costas array in this model is calculated by using a helper matrix where the n'th row represents the nth difference of the Costas array. This means that we just have to use the upper triangular matrix (the lower triangular is set to a constant value). For this we use the handy slice method which extracts just the part of the row we need:
    for(int i = 0; i < n-1; i++) {
       distinct(*this, diffs.slice(i+1,n,i,i+1), opt.icl());
    }
    
Symmetry breaking
This model use one symmetry breaking option (-symmetry min) which requires that the first element in the costas array must be the minimum.
if (opt.symmetry() == SYMMETRY_MIN) {
  min(*this, costas, costas[0], opt.icl());
}
For an array of 6, with this symmetry breaking there are 19 solutions (without: 119 solutions).

Divisible by 9 through 1 problem

divisible_by_9_through_1.cpp

The problem is from Solving Combinatory Problems with LINQ:
Find a number consisting of 9 digits in which each of the digits from 1 to 9 appears only once. This number must also satisfy these divisibility requirements:

1. The number should be divisible by 9.
2. If the rightmost digit is removed, the remaining number should be divisible by 8.
3. If the rightmost digit of the new number is removed, the remaining number should be divisible by 7.
4. And so on, until there's only one digit (which will necessarily be divisible by 1).
The Gecode code for this is (basically):
distinct(*this, digits, opt.icl());
for(int i = 0; i < n; i++) {
  int m = base-i-1;
  IntVarArray digits_slice(*this, digits.slice(0, 1, m));
  to_num(*this, digits_slice, t[i], base, opt.icl());
  rel(*this, t[i] % m == 0);
}
branch(*this, digits, INT_VAR_SIZE_MIN, INT_VAL_SPLIT_MAX); 
slice for arrays
As I understand it, slice for arrays is new in Gecode 3.4.0 (there have been a slice for matrices in earlier versions) and is very handy.

The above code could have been written somewhat more compact, by doing the slice part in the call to to_num, but it don't looks as nice.
to_num(*this, 
       IntVarArray(*this, digits.slice(0, 1, m)), 
       t[i], 
       base, 
       opt.icl());
A related note: The constraint to_num which ensures that the array x contains the digitss (and in correct order) of the number z in base base can now be written as follows. sum(coeffs, x) == z is a multiplication of the array x with the array coeffs. In this case, however, it takes slightly more propagations than using the linear variant.
void to_num(Space & space, IntVarArray x, IntVar z, int base = 10, IntConLevel icl = ICL_BND) {
  int len = x.size();
  IntArgs coeffs(len);
  for(int r = 0; r < len; r++) {
    coeffs[r] = pow(base, len-r-1);
  }
  // linear(space, coeffs, x, IRT_EQ, z, icl); // older version
  rel(space, sum(coeffs, x) == z, icl); // alternative version
}
Solutions
Due to integer overflow, this model cannot handle base > 10.

Answer: 381654729 t: {381654729, 38165472, 3816547, 381654, 38165, 3816, 381, 38, 3} digits: {3, 8, 1, 6, 5, 4, 7, 2, 9} (in base 10) The array t is the progression of the truncated number (in base 10), and the array digits contains the digits used.

For base=8 there are 3 solutions. (Note that the answer is in base 10.)
Answer: 1538257
t: {1538257, 192282, 24035, 3004, 375, 46, 5}
digits: {5, 6, 7, 4, 3, 2, 1} (in base 8)

Answer: 1391089
t: {1391089, 173886, 21735, 2716, 339, 42, 5}
digits: {5, 2, 3, 4, 7, 6, 1} (in base 8)

Answer: 874615
t: {874615, 109326, 13665, 1708, 213, 26, 3}
digits: {3, 2, 5, 4, 1, 6, 7} (in base 8)
Here is all solutions from base 2..10 where the number is in base 10. 381654729 ([3,8,1,6,5,4,7,2,9])
BaseSolutions, base 10 ([digits in base])
21 ([1])
3-
457 ([3,2,1]), 27 ([1,2,3])
5-
67465 ([5,4,3,2,1]), 2285 ([1,4,3,2,5])
7-
81538257 ([5,6,7,4,3,2,1]), 1391089 ([5,2,3,4,7,6,1]), 874615 ([3,2,5,4,1,6,7])
9
10


Compare with other implementations in other systems:

Broken weights

Gecode model: broken_weights.cpp

This problem is from Math Less Traveled:
Here's a fantastic problem I recently heard. Apparently it was first posed by Claude Gaspard Bachet de Méziriac in a book of arithmetic problems published in 1612, and can also be found in Heinrich Dorrie's 100 Great Problems of Elementary Mathematics.
"""
A merchant had a forty pound measuring weight that broke into four pieces as the result of a fall. When the pieces were subsequently weighed, it was found that the weight of each piece was a whole number of pounds and that the four pieces could be used to weigh every integral weight between 1 and 40 pounds. What were the weights of the pieces?
"""
Note that since this was a 17th-century merchant, he of course used a balance scale to weigh things. So, for example, he could use a 1-pound weight and a 4-pound weight to weigh a 3-pound object, by placing the 3-pound object and 1-pound weight on one side of the scale, and the 4-pound weight on the other side.
It is a rather simple problem, much like the coins problem (coins3.cpp) where the object is to find a combination of coins (of a certain nomination) to be able to give back changes for all values 1 to 99.

There is one significant difference between these problems, however: in this weights problem, the weights can be on either side of the balance scale, so instead of a simple 0..n representation (how many, is any, of each coin/weights to use), we use {-1,0,+1} where -1 means that a weight is on the left side of the scale and +1 means it is on the right size, and 0 means it is unused.

The main Gecode model is shown below. weights is the weights to use (of size 4), and orig_weight is the total weight (the original weight that was broken, here 40). x (and it's matrix alias x_m) is the representation of which weights to use ({-1,0,1 }) for each combination (from 1..40). Also, not shown here, we minimize the element last in the sorted weights array.
// a matrix version of the different combinations of weights to use
Matrix<IntVarArgs> x_m(x, num_weights, orig_weight);

// symmetry breaking: order the weights
rel(*this, weights, IRT_LQ, opt.icl());

// sum of the weights is w
linear(*this, weights, IRT_EQ, orig_weight, opt.icl());

// all different weights from 1..40 must be combined
for(int w = 1; w <= orig_weight; w++) {
  IntVarArray tmp(*this, num_weights, -orig_weight, orig_weight);
  for(int c = 0; c < num_weights; c++) {
    rel(*this, weights[c]*x_m(c,w-1) == tmp[c], opt.icl());
  }
  rel(*this, sum(tmp) == w, opt.icl());
}

branch(*this, weights, INT_VAR_DEGREE_MAX, INT_VAL_RANGE_MIN);
As noted above, this is a simple problem (and model). Some comments:
  • It took me some time to realize that the tmp array must have a range of -orig_weight..orig_weight.
  • branching: We just need to branch on the weights. One of the first tries, I branched just on x which was a bad idea (or I happened to pick the wrong variable/value selection).
  • Note the use of the "alias" sum for summing the tmp array.
Options
Well, the above solved the specific problem with original weight (orig_weight) of 40 and 4 pieces (num_weights). However, the model then developed in a more general and can now handle any (or should I write "any") combination of original weight and number of pieces.

Gecode don't have direct support for this kind of off-standard command lines options (there are a couple standard options, though). There is the much used size option, which is often used for selecting a specific problem, or a size of some kind. But here we want to have two different options, so a dedicated option class was written:
class BrokenWeightsOptions : public Options {
private:
  Driver::UnsignedIntOption _num_weights; // number of weights
  Driver::UnsignedIntOption _orig_weight; // original weight
public:
  // Initialize options
  BrokenWeightsOptions(const char* n)
    : Options(n),
      _num_weights("-num_weights",
                   "number of weights",
                   4),
      _orig_weight("-orig_weight",
                   "original weight",
                   40) {
    add(_num_weights);
    add(_orig_weight);
  }
  // Parse options from arguments argv (number is argc)
  void parse(int& argc, char* argv[]) {
    Options::parse(argc,argv);
  }

  unsigned int num_weights(void) const { return _num_weights.value(); }
  unsigned int orig_weight(void) const { return _orig_weight.value(); }
};
Now we could test different problem, e.g. if there could be 3 number of pieces instead of 4: broken_weights -num_weights 3 -orig_weight 40 Answer: no, it could not.

For the problem of original weight of 50 and 5 broken weights, the model came up with this solution (remember, we minimize the largest elements of the weights array):
weights: {1, 3, 9, 18, 19}
Another feature is the -search option, which by default is bab (branch & bound). Using -dfs (depth first search), all solutions is given instead of the minimal solution (or rather the progression of minimal solutions).

Compare with the following implementations:

Strimko / Chain Sudoku

In Strimko - Latin squares puzzle with "streams" (August 2009), I blogged about Strimko (a.k.a. Chain Sudoku) - then a rather new grid puzzle - based on Latin squares. For more about Strimko, see the references in that blog post.

The Gecode model for solving Strimko problems (including 6 instances) is strimko2.cpp. Some of the constraints are shown below:
  • the Latin Square constraint is modeled rather simple with the use of Matrix alias.
  • the new feature of array concatenation of IntVarArgs. stream << x[i*n+j]; means: for each position in stream that belongs to "this" stream st, push the corresponding element in the decision variable array (matrix) x to the temporary array stream. All the values in stream must then be distinct.
Matrix<IntVarArray> x_m(x, n, n);
// Latin Square
for (int i = 0; i < n; i++) {
  distinct(*this, x_m.row(i), opt.icl());
  distinct(*this, x_m.col(i), opt.icl());
}

// streams
for(int st = 1; st <= n; st++) {
  IntVarArgs stream;
  for(int i = 0; i < n; i++) {
    for(int j = 0; j < n; j++) {
      if (streams[i*n+j] == st) {
        stream << x[i*n+j];
      }
    }
  }
  distinct(*this, stream, opt.icl());
}
The problem also state some fixed hints in the grid, but the code for handling this is not shown. Compare with the following models:

Futoshiki puzzle

Futoshiki puzzles are another Latin square based puzzles, with the additional twist that there are less-than (and greater-than) hints. Here is an example from Wikipedia:



The Gecode model futoshiki.cpp is very much like Strimko model (modulo the different type of hints), so I don't show any code here. The program includes includes 3 examples, one is the Wikipedia example shown above.

Compare with the following models:

Latin square card puzzle

This problem is from Mario Livio's book about group theory "The Equation that couldn't be solved", page 22:
... Incidentally, you may get a kick out of solving this eighteenth century card puzzle: Arrange all the jacks, queens, kings, and aces from a deck of cards in a square so that no suit or value would appear twice in any row, column, or the two main diagonals.
The Gecode model is latin_square_card_puzzle.cpp contains just a bunch of distinct (all different) constraints for distinct rows, columns, and the two diagonals.

The representation (for n=4) is rather simple: the value is the digit (here 0..3), and the 10's is the suits (0's, 10's, 20's, and 30's) and is access by mod respectively division with 10. So the complete list of valid values are
// values: i mod 10 
0, 1, 2, 3,  // suite 0: 0 div 10
10,11,12,13, // suite 1: 1 div 10
20,21,22,23, // suite 2: 2 div 10
30,31,32,33  // suite 3: 3 div 10
The initial domain of the grid (x) is 0..n*10, but it is reduced by these valid values via an IntSet, and the function dom.
x(*this, n*n, 0, n*10)
// ...
// create all the valid values
IntArgs cards_a;
for(int i = 0; i < n; i++) {
   for(int j = 0; j < n; j++) {
     cards_a << i+m*j;
   }
}
IntSet cards(cards_a); // convert to a IntSet
dom(*this, x, cards);  // restrict the domain
Compare with the MiniZinc model latin_square_card_puzzle.mzn (where the construction of all the alldifferent's is much easier).

Note: There is a solution of n = 4 and n = 5, but not for n = 6. The n = 6 problem is the same as Euler's 36 officer's problem, which thus is not solvable. Also see MathWorld

Latin squares

Gecode model: latin_squares.cpp.

Just a simple decomposition of Latin squares constraint using Gecode's Matrix wrapper of a n*n IntVarArray
void latin_square(Space& space, Matrix m, 
                  IntConLevel icl = ICL_DOM) {
  int n = m.width();
  for(int i = 0; i < n; i++) {
    distinct(space, m.row(i), icl);
    distinct(space, m.col(i), icl);
  }
}
It is called by the following:
Matrix m(x, n, n);
latin_square(*this, m, opt.icl());

Tourist site competition

Gecode model: tourist_site_competition.cpp

This problem is from from Pierre Flener's presentation Constraint Technology - A Programming Paradigm on the Rise (PDF), pages 5f: problem statement, pages 12f: model, pages 21ff: walktrough of a solution. Here with 7 tourist sites and 7 judges:
Every tourist site is visited by r = 3 judges. Every judge visits c = 3 tourist sites. Every pair of sites is visited by lambda = 1 common judge.
There are 151200 solutions to this problem. With the additional symmetry breaking constraint that Ali (judge 0 in the model) should visit Birka, Falun and Lund (sites 0,1,2) there are 4320 solutions.

This problem was also presented as "The Airline-of-the-Year Problem" in Flener's presentation Constraint Programming - Programming Paradigm on the Rise, page 4f. The problem is stated as follows for 7 airlines and 7 judges:
Constant jury: Every airline is tested by 3 judges. Constant load: Every judge tests 3 airlines. Equity: Every airline pair is tested by 1 common judge.
The model is a quite straight forward translation of the MiniZinc model tourist_site_competition.mzn.

One note: The code for showing which sites a judge visits, and which judges visits a site is done with the following two channel constraints:
// declarations
BoolVarArray x; 
SetVarArray judges_where; // where are the judges
SetVarArray sites_who;    // who visits this sites
Matrix x_m(x, num_judges, num_sites);
// ..
// Where are the judges?
for(int j = 0; j < num_judges; j++) {
   channel(*this, x_m.col(j), judges_where[j]);
}
// Which judges visits the sites?
for(int s = 0; s < num_sites; s++) {
  channel(*this, x_m.row(s), sites_who[s]);
}

Scheduling speakers

scheduling_speakers.cpp. This problem is from from Rina Dechter's book "Constraint Processing", page 72 where the object is to schedule 6 speakers to 6 slots.

It is a very simple model, and the only problem was how to convert the list of available slots to set variable. Here is my solution, and maybe there is a better way,
3,4,5,6,
3,4,
2,3,4,5,
2,3,4,
3,4,
1,2,3,4,5,6
After first trying a more general but complicated variant (which is shown in the model), I settled with this simpler one, which works fine for this small example:
IntSetArgs available(n);
available[0] = IntSet( IntArgs() << 3 << 4 << 5 << 6 );
available[1] = IntSet( IntArgs() << 3 << 4 );
available[2] = IntSet( IntArgs() << 2 << 3 << 4 << 5 );
available[3] = IntSet( IntArgs() << 2 << 3 << 4 );
available[4] = IntSet( IntArgs() << 3 << 4 );
available[5] = IntSet( IntArgs() << 1 << 2 << 3 << 4 << 5 << 6 );
Then the constraints can be written
const static int n = 6;
// ...
x(*this, n, 1, n);
// ...
distinct(*this, x, opt.icl());
for(int i = 0; i < n; i++) {
   // rel(*this, SetVar(*this, available[i],available[i]), SRT_SUP, x[i]);
   rel(*this, singleton(x[i]) <= available[i]);
}
Where the for loop corresponds to this high-level code forall(i in 1..n) (x[i] in available[i]).

PERT

Gecode model: pert.cpp.

This is a simple PERT model in Gecode, from Pascal van Hentenryck Scheduling and Packing In the Constraint Language cc(FD), page 7f.

Compare with the following models:

Lichtenstein coloring problem

Gecode model: lichtenstein_coloring.cpp.

This problem is from bit-player: The chromatic number of Liechtenstein
It seems that Liechtenstein is divided into 11 communes, which emphatically do not satisfy the connectivity requirement of the four color map theorem. Just four of the communes consist of a single connected area (Ruggell, Schellenberg and Mauren in the north, and Triesen in the south). ... In the map above, each commune is assigned its own color, and so we have an 11-coloring. It’s easy to see we could make do with fewer colors, but how many fewer? I have found a five-clique within the map; that is, there are five communes that all share a segment of border with one another. It follows that a four-coloring is impossible. Is there a five-coloring? What is the chromatic number of Liechtenstein?
Also, see Mikael Johansson's post at Michi's blog On the chromatic number of Lichtenstein where I got the connections between communes/enclaves of Lichtenstein.

Apart from quite a lot of preparations, in terms of initializing arrays etc, this model was surprisingly easy to convert from the MiniZinc model (lichtenstein_coloring.mzn).

An example: the symmetry breaking constraint to ensure that we must take the colors in order - i.e. start from color 0, then 1, and so on - we can now (in Gecode 3.4) use the following; it was slightly less writable/readable in earlier versions.
for(int c = 1; c < num_colors; c++) {
  rel(*this, (color_used[c]==1) >> (color_used[c-1]== 1));
}
With this and the other symmetry breaking constraint that we assign a particular commune (Balzers) with the color 0, there are 1872 solutions. They are shown when using -search dfs.

Also, compare with the following models:

Averbach seating problem

Gecode model: averbach_1.4.cpp.

This is Problem 1.4 from Averbach & Chein "Problem Solving Through Recreational Mathematics":
Messr Baker, Dyer, Farmer, Glover, and Hosier are seated around a circular table, playing poker. Each gentleman is the namesake of the profession of one of the others. The dyer is seated two places to the left of Mr Hosier. The baker sits two places to Mr Baker's right. The farmer is seated to the left of Mr Farmer. Mr Dyer is on the glover's right. What is the name of the dyer?
The only tricky part here was the modulo constraints (and these constraints are about all there is). The constraint The dyer is seated two places to the left of Mr Hosier can be translated into the high-level expression dyer = (Hosier - 2) mod 5 which is nearly exactly how to express it in Gecode:
rel(*this, baker == (Baker + 2) % 5);
This could also be written by explicit use the mod constraint:
IntVar c5(*this, 5, 5);
mod(*this, expr(*this, Baker + 2),  c5, baker);
As you probably have understood now, I prefer the first, shorter version.

Fill-a-pix

Gecode model: fill_a_pix.cpp

From Conceptis Puzzles: Fill-a-Pix rules:
Fill-a-Pix is a Minesweeper-like puzzle based on a grid with a pixilated picture hidden inside. Using logic alone, the solver determines which squares are painted and which should remain empty until the hidden picture is completely exposed.
Given a grid of hints with the number of painted squares around a specific square, the object is to figure out (pun intended) the painted squares. X refers to an unknown (and is represented with -1 in the model).
X,X,X,X,X,X,X,X,0,X,
X,8,8,X,2,X,0,X,X,X,
5,X,8,X,X,X,X,X,X,X,
X,X,X,X,X,2,X,X,X,2,
1,X,X,X,4,5,6,X,X,X,
X,0,X,X,X,7,9,X,X,6,
X,X,X,6,X,X,9,X,X,6,
X,X,6,6,8,7,8,7,X,5,
X,4,X,6,6,6,X,6,X,4,
X,X,X,X,X,X,3,X,X,X
This problem has just one combined constraint, and again the new syntactic sugar makes it rather easy to state: for each square which is not X, we require that there are this number of neighbours which are painted (has value 1). n is the dimension of the grid and prob is the hints of the problem instance (an array of integers).
for(int i = 0; i < n; i++) {      
  for(int j = 0; j < n; j++) {
    // get the data from the instance
    int p = prob[c++]; 
    if (p > X) {
      IntVarArgs tmp;
      // must be inside the grid
      for(int a = -1; a <= 1; a++) {
        for(int b = -1; b <= 1; b++) {
          if (i+a >= 0 && i+a < n &&
              j+b >= 0 && j+b < n) {
            tmp << x[(i+a)*n+(j+b)];
          }
        }
      }
      rel(*this, p == sum(tmp));
    }
  }
}
This model was inspired/derived from my MiniZinc model (fill_a_pix.mzn which in turn was derived from my Minesweeper in MiniZinc (minesweeper.mzn).

Compare with the following models: Also, see with the Minesweeper example from the Gecode distribution: minesweeper.cpp.

Minesweeper 2

Gecode model: minesweeper2.cpp

Since the Fill-a-pix problem (see above) is quite like the Minesweeper problem, I also implemented a Minesweeper model based on the Fill-a-pix model.

The first 10 problem instances was borrowed from the Minesweeper example from the Gecode distribution (minesweeper.cpp). I added the 7 instances that was included with the MiniZinc model (see my MiniZinc page for a list of these instances); some of these are not square matrices.

Here is the main constraint for the Minesweeper model. It is very much the same as for Fill-a-pix, with some exceptions:
  • It supports non-square problems
  • Two extra constraints are added:
    • If a cell has a hint, then it cannot be a bomb
    • If a cell contains a bomb then it cannot be numbered.
for(int i = 0; i < rows; i++) {      
  cout << "  ";
  for(int j = 0; j < cols; j++) {
    int p = prob[c++]; // get data
    IntVar pp(*this, p, p);
    rel(*this, (pp > XX) >> (x[i*cols+j] == 0));
    rel(*this, (x[i*cols+j] == 1) >> (pp == XX));
    if (p > X) {
      IntVarArgs tmp;
      for(int a = -1; a <= 1; a++) {
        for(int b = -1; b <= 1; b++) {
          if (i+a >= 0 && i+a < rows &&
              j+b >= 0 && j+b < cols) {
            tmp << x[(i+a)*cols+(j+b)];
          }
        }
      }
      rel(*this, p == sum(tmp));
    }
  }
}

Clock triplets

Gecode model: clock_triplets.cpp. Problem formulation from the F1 Compiler example:
Dean Clark's Problem (Clock Triplets Problem)
The problem was originally posed by Dean Clark and then presented to a larger audience by Martin Gardner. The problem was discussed in Dr. Dobbs's Journal, May 2004 in an article by Timothy Rolfe. According to the article, in his August 1986 column for Isaac Asimov's Science Fiction Magazine, Martin Gardner presented this problem:
"""
Now for a curious little combinatorial puzzle involving the twelve numbers on the face of a clock. Can you rearrange the numbers (keeping them in a circle) so no triplet of adjacent numbers has a sum higher than 21? This is the smallest value that the highest sum of a triplet can have.
"""

Mr Greenguest fancy dress problem

Gecode model: fancy.cpp.

Problem formulation and LPL code:
Mr. Greenfan wants to give a dress party where the male guests must wear green dresses. The following rules are given: 1 If someone wears a green tie he has to wear a green shirt. 2 A guest may only wear green socks and a green shirt if he wears a green tie or a green hat. 3 A guest wearing a green shirt or a green hat or who does not wear green socks must wear a green tie. 4 A guest who is not dressed according to rules 1-3 must pay a $11 entrance fee. Mr Greenguest wants to participate but owns only a green shirt (otherwise he would have to pay one for $9). He could buy a green tie for $10, a green hat (used) for $2 and green socks for $12. What is the cheapest solution for Mr Greenguest to participate?

Jobs puzzle

Gecode model: jobs_puzzle.cpp.

This is a standard problem in Automatic Reasoning. Problem formulation from Larry Wos' problem page:
Jobs Puzzle There are four people: Roberta, Thelma, Steve, and Pete. Among them, they hold eight different jobs. Each holds exactly two jobs. The jobs are chef, guard, nurse, clerk, police officer (gender not implied), teacher, actor, and boxer. The job of nurse is held by a male. The husband of the chef is the clerk. Roberta is not a boxer. Pete has no education past the ninth grade. Roberta, the chef, and the police officer went golfing together. Question: Who holds which jobs?

Heterosquare

Gecode model: heterosquare.cpp. Problem from Comet's old Wiki:
A heterosquare of order n is a n*n square whose elements are distinct integers from 1 to n^2 such that the sums of the rows, columns and diagonals are all different. Here is an example of heterosquare of order 3 19 1 2 3 6 8 9 4 21 7 6 5 18 16 17 12 15 (Sums)
The constraints are shown below. One can note the expression sum(m.row(i)) == row_sums[i] (i.e. sum over a row in the matrix); I wasn't sure if it would work. I have also noted that I've been lazy and use the append array operator (<<) quite much.
Matrix m(x, n, n);
// all the entries in the matrix should be different
distinct(*this, x);

// and all sums should be different
IntVarArgs all_sums;
all_sums << row_sums; // append to the array all_sums
all_sums << col_sums;
all_sums << diag1;
all_sums << diag2;    
distinct(*this, all_sums);

// rows/column sums and diagonals
IntVarArgs v_diag1;
IntVarArgs v_diag2;
for(int i = 0; i < n; i++) {
  rel(*this, sum(m.row(i)) == row_sums[i]);
  rel(*this, sum(m.col(i)) == col_sums[i]);
  v_diag1 << m(i,i);
  v_diag2 << m(n-i-1,i);
}

rel(*this, sum(v_diag1) == diag1);
rel(*this, sum(v_diag2) == diag2);
Some trivia: Without any symmetry breaking, there are 24960 solution of order 3, i.e. a 3 by 3 matrix. The first one is:
            | 14 (diag2)
  1   2   3  =   6
  4   5   8  =  17
  6   9   7  =  22
---------------
 11  16  18 | 13 (diag1)
Compare with the following implementations:

Some explorations of ISBN13

Gecode model: isbn.cpp.

This model is just for exploring ISBN13.

Put the ISBN (with 12 or 13 digits) to check at the command line: ./isbn 978052112549, and the program will print the check digit (9). If we put a shorter ISBN13, e.g with 11 digits (97805211254), then the program will print all the ISBN13 that matches, i.e. will calculate the two last digits in the number:
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 7, 1} checkdigit: 1
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 6, 2} checkdigit: 2
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 5, 3} checkdigit: 3
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 4, 4} checkdigit: 4
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 3, 5} checkdigit: 5
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 2, 6} checkdigit: 6
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 1, 7} checkdigit: 7
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 0, 8} checkdigit: 8
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 9, 9} checkdigit: 9
Note: The digit check for ISBN uses two constants 3 and 1 (which I call mult0 and mult1 in the model). If we let these two "free" (see below how to do that) then there are 90 different numbers that satisfies the first 12 digits. Some of them are (chosen to have not the same check digit):
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 9, 1} checkdigit: 1
mult0: 1
mult1: 0
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 9, 1} checkdigit: 1
mult0: 1
mult1: 5
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 9, 1} checkdigit: 1
mult0: 3
mult1: 3
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 9, 5} checkdigit: 5
mult0: 9
mult1: 6
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 9, 6} checkdigit: 6
mult0: 0
mult1: 1
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 9, 8} checkdigit: 8
mult0: 8
mult1: 5
ISBN13: {9, 7, 8, 0, 5, 2, 1, 1, 2, 5, 4, 9, 9} checkdigit: 9
mult0: 1
mult1: 3
The mult's can be stated on command line:
  ./isbn ISBN mult0 mult1
Example: isbn 978052112549 3 1 for the default multiplicators. The value 11 (or any value larger than 9) is to let one mult free, e.g. isbn 978052112549 11 11 for letting both free, where we get the 90 solutions mentioned above.

Compare with the following models:

Covering (OPL)

Gecode model: covering_opl.cpp.

This problem is from the OPL example cover.mod, where the object is to find a minimum cover of workers for a set of tasks. See the Comet model covering_opl.co for a fairly OPL-like model.

I thought it would be easy to model this problem in Gecode. This Comet constraint is about the only constraint in the model (except for the cost calculation), and it ensures that there is at least one qualified worker for each task:
forall(j in Tasks)
  m.post(sum( c in Qualified[j] ) 
       Hire[c] >= 1);
However, it took quite a time to get this correct. Here is the different stages of the model.

My first approach was to translate this to the following Gecode snippet. Qualified is an IntSetArgs array of the workers qualified for each task, Hire is an IntVarArray of values 0..1, indicating that a workers is hired. The code loop through all the tasks and each workers (w) to sum the qualified and hired workers. We have two boolean arrays here: is_qualified[w] is true (i.e. 1) if this worker is qualified for the task, and is_qualified_and_hired[w] is set if this worker is qualified and hired.
for(int t = 0; t < num_tasks; t++) {
  SetVar s(*this, Qualified[t], Qualified[t]);
  BoolVarArray is_qualified(*this, nbWorkers, 0, 1);
  BoolVarArray is_qualified_and_hired(*this, nbWorkers, 0, 1);
  for(int w = 0; w < nbWorkers; w++) {
    // is this worker qualified for this task?
    rel(*this, s, SRT_SUP, IntVar(*this, w, w), is_qualified[w]);
    // if this worker is qualified _and_ hired 
    // then it's a count
    rel(*this, (is_qualified[w] && Hire[w] == 1) == 
       (is_qualified_and_hired[w] == 1));
  }
  // there must be some worker hired for this task
  rel(*this, sum(is_qualified_and_hired) >= 1);
}
We have seen the set operator SRT_SUP before, in the Scheduling speakers, and like that problem, some trickery was needed to convert the set of qualified workers to this model (and that is more a C++ issue than a Gecode thing).

After some thought, I changed to this more compact version using the set constraint in an expr:
    for(int t = 0; t < num_tasks; t++) {
      SetVar s(*this, Qualified[t], Qualified[t]);
      BoolVarArray is_qualified_and_hired(*this, nbWorkers, 0, 1);
      for(int w = 0; w < nbWorkers; w++) {
        // if this worker qualified _and_ hired then it's a count 
        rel(*this, (expr(*this, s >= IntSet(w,w)) && Hire[w] == 1) == 
            (is_qualified_and_hired[w] == 1));
      }
      // must be some worker hired for this task
      rel(*this, sum(is_qualified_and_hired) >= 1);
    }
I would rather like to loop over just the qualified workers in the Qualified[t] set, but I didn't know how to do that yet.

Ah. Some minutes later I figured it out (by reading the documentation about IntSet in more detail). This is definitely more like it:
for(int t = 0; t < num_tasks; t++) {
  IntSet tt(_QualifiedSet[t]);
  BoolVarArgs bb;
  for(int w = 0; w < nbWorkers; w++) {
    // is this worker qualified?
    if (tt.in(w)) {
      // then: is he/she hired?
      bb << expr(*this, Hire[w] == 1);
    }
  }
  // at least one worker must hired for this task
  rel(*this, sum(bb) >= 1);
}

Pi Day Sudoku 2009

Gecode model: sudoku_pi.cpp.

Problem from Brain Freeze Puzzles/a>, and 360 Pi Day Sudoku 2009:
Each row, column, and region contains the digits 1-9 exactly once plus three Pi symbols.
I wrote about this problem in Pi Day Sudoku 2009 - the models (MiniZinc and Comet), and the two models in MiniZinc (sudoku_pi.mzn) and Comet (sudoku_pi.co).

The Gecode model was surprisingly easy to do, maybe except for changing from 1-based to 0-based indexing for the hints and using an array based representation instead of a matrix proper. The constraints is just a lot of global cardinality constraint (count in Gecode); we cannot use the alldifferent constraints (distinct in Gecode) since there are (exactly) three occurrences of Π (this symbol should be a fancy Pi) in each row/column/region.

Set partition

Gecode model: set_partition.cpp.

Set partition problem. From Koalog:
Given the set S = {1, 2, ..., n}, it consists in finding two sets A and B such that: * A union B = S * |A| = |B| * sum(A) = sum(B) * sum_squares(A) = sum_squares(B)
This model uses set variables and set operations for union, cardinality etc. The sums and squared sums are calculated by using the set variable method weights.

In the Gecode distribution there is also a model of this problem. However it use integer variables and a lot of redundant/efficiency constraints.

Mr Smith problem

Gecode model: mr_smith.cpp.

Logic problem from an IF Prolog example:
The Smith family and their three children want to pay a visit but they do not all have the time to do so. Following are few hints who will go and who will not: o If Mr Smith comes, his wife will come too. o At least one of their two sons Matt and John will come. o Either Mrs Smith or Tim will come, but not both. o Either Tim and John will come, or neither will come. o If Matt comes, then John and his father will also come.
Here the new boolean operators in Gecode shines. In earlier version this would be much harder to write (and read):
BoolVar 
   Mr_Smith(L[0]), 
   Mrs_Smith(L[1]), 
   Matt(L[2]), 
   John(L[3]), 
   Tim(L[4]);

// If Mr Smith comes, his wife will come too.
rel(*this, Mr_Smith >> Mrs_Smith);

// At least one of their two sons Matt and John will come.
rel(*this, Matt || John);

// Either Mrs Smith or Tim will come, but not both.
rel(*this, Mrs_Smith + Tim == 1);

// Either Tim and John will come, or neither will come.
rel(*this, Tim == John);

// If Matt comes, then John and his father will also come.
rel(*this, Matt >> (John && Mr_Smith));

Talisman square

Gecode model: talisman_square.cpp.

From MathWorld Talisman Square:
An n x n array of the integers from 1 to n^2 such that the difference between any one integer and its neighbor (horizontally, vertically, or diagonally, without wrapping around) is greater than or equal to some value k is called a (n,k)-talisman square.
Since this problem used two parameters (n and k) I wrote a special option class (using the standard SizeOption just gives the possibility of one optional parameter).
class TalismanSquareOptions : public Options {
private:
  Driver::UnsignedIntOption _n_option;
  Driver::UnsignedIntOption _k_option;
public:
  TalismanSquareOptions(const char* n) 
    : Options(n),
      _n_option("-n",
                "n value",
                5),
      _k_option("-k",
                "k value",
                4)
  {
    add(_n_option);
    add(_k_option);
  }
  void parse(int& argc, char* argv[]) {
    Options::parse(argc,argv);    
  }
  unsigned int k(void) const  { return _k_option.value();  }
  unsigned int n(void) const  { return _n_option.value();  }
};
And then, the program can be called with the following parameters
./talisman_square -k 3 -n 10

Curious numbers

Gecode model: cur_num.cpp.

Problem: Curious Numbers (#114) from Dudeney "Amusements in Mathematics".

Curious set of integers

Gecode model: curious_set_of_integers.cpp.

From Martin Gardner:
The integers 1,3,8, and 120 form a set with a remarkable property: the product of any two integers is one less than a perfect square. Find a fifth number that can be added to the set without destroying this property.

Bin packing problems

Gecode model: bin_packing.cpp.

This is a rather simple, or at least straightforward, model of bin packing. It includes the same 9 problem as the SICStus Prolog model (bin_packing.pl).

There is an extra option (-symmetry sort) which sorts the entries (the stuff array) before trying to pack, and it is - to no surprise - quite faster.

Exodus (Dell Logic Puzzles)

Gecode model: exodus.cpp.

One new addition of rel-expressions is element which is used in this model. Instead of the following with temporary IntVar:s and element constraints:
IntVar Age_Yemen(*this, dom_ages);
element(*this, Age, Yemen, Age_Yemen);
IntVar Age_Ethiopia(*this, dom_ages);
element(*this, Age, Ethiopia, Age_Ethiopia);
We can now simply write:
rel(*this, element(Age,Yemen) < element(Age,Ethiopia));
However, the following is still not possible to write since Yemen and Ethiopia is IntVar:
rel(*this, Age[Yemen] < Age[Ethiopia]);
Maybe this will come is later version?

Note: As I noted this use of element expression rather late, not all models use it. Also, sometimes it is better to use the temporary version and element constraint, for example where the domain of the (temporary) variable should be tweaked in some way.

Scheduling problem I

Gecode model: schedule1.cpp.

Scheduling problem from SICStus Prolog.

This model use the new scheduling constraint cumultive which is a simpler version of the existing constraint cumulatives. (See Scheduling with the cumulatives constraint in Gecode for more about cumulatives.)

Set covering problem II

Gecode model: set_covering2.cpp.

Set covering problem from Taha: "Operations Research - An Introduction". Example 9.1-2: Minimize the number of security telephones in street corners on a campus.

Set covering problem III

Gecode model: set_covering3.cpp.

Set covering problem from Murty: "Optimization Models for Decision Making", page 302f.

Set partition/set covering problem

Gecode model: set_covering4.cpp.

Problem from Lundgren, Rönnqvist, Värbrand "Optimeringslära", page 408: minimize the cost of the alternatives which covers all the objects. This model has also an option for solving it either as set partition problem (parameter 0) or as a set covering problem (parameter 1).

Set covering (Skiena)

Gecode model: set_covering_skiena.cpp.

From Steven Skiena: The Stony Brook Algorithm Repository. Set cover.

Combinatorial auction

Gecode model: combinatorial_auction.cpp.

This example is from the Wikipedia article Combinatorial_auction. It is here implemented as a set partition problem.

Just forgotten problem (Enigma 1517)

Gecode model: just_forgotten.cpp.

Huey, Dewey and Louie problem

Gecode model: huey_dewey_louie.cpp.

K4P2 Graceful Graph

Gecode model: K4P2GracefulGraph2.cpp.

3 jugs problem

Gecode model: 3_jugs2.cpp.

The famous 3 jugs problem with a constraint programming bent (or MIP bent if you like it).

Knapsack investments problem

Gecode model: knapsack_investments.cpp.

Decide which projects should be investment in, with some extra requirements.

Decomposition of global constraint all_differ_from_at_least_k_pos

Gecode model: all_differ_from_at_least_k_pos.cpp.

Decomposition of global constraint all_equal

Gecode model: all_equal.cpp.

Decomposition of global constraint all_min_dist

Gecode model: all_min_dist.cpp.

Decomposition of global constraint alldifferent_cst

Gecode model: alldifferent_cst.cpp.

Decomposition of global constraint alldifferent_modulo

Gecode model: alldifferent_modulo.cpp.

Decomposition of global constraint alldifferent_on_intersection

Gecode model: alldifferent_on_intersection_modulo.cpp.

Decomposition of global constraint among

Gecode model: among.cpp.

Decomposition of global constraint among_seq

Gecode model: among_seq.cpp.

Decomposition of global constraint bin_packing

Gecode model: bin_packing2.cpp.

Decomposition of global constraint distribute

Gecode model: distribute.cpp.

Decomposition of global constraint inverse

Gecode model: inverse.cpp.

Averbach seating problem 1.2

Gecode model: averbach_1.2.cpp.

This is another seating problem from Averbach & Chein, problem 1.2.

Averbach seating problem 1.3

Gecode model: averbach_1.3.cpp.

A logical puzzle (men, wifes and ponies) from Averbach & Chein, problem 1.3.

Hamming distance

Gecode model: hamming_distance.cpp.

Hanging weights puzzle

Gecode model: hanging_weights.cpp.

Problem from Using LINQ to solve puzzles.

Magic hexagon puzzle (CSPLib problem 23)

Gecode model: magic_hexagon.cpp.

This is problem 23 from CSPLib. Also, see the model (and comments) in ESSENCE.

Bales of Hay problem

Gecode model: bales_of_hay.cpp.

Problem from The Math Less Traveled: The haybaler.

Warehouse location problem

Gecode model: warehouse.cpp.

From OPL model warehouse.mod. Note: There is a warehouses model in the Gecode distribution that solves the same problem, and that is also used as case study example in the excellent "Modeling and Programming with Gecode" (which I read some month ago).

However, my Gecode model was translated rather directly from the Comet model warehouse.co and without looking at the distributed model.

Marathon puzzle

Gecode model: marathon2.cpp.

The problem is from an example of Xpress, but I cannot find the page.
Dominique, Ignace, Naren, Olivier, Philippe, and Pascal have arrived as the first six at the Paris marathon. Reconstruct their arrival order from the following information: a) Olivier has not arrived last b) Dominique, Pascal and Ignace have arrived before Naren and Olivier c) Dominique who was third last year has improved this year. d) Philippe is among the first four. e) Ignace has arrived neither in second nor third position. f) Pascal has beaten Naren by three positions. g) Neither Ignace nor Dominique are on the fourth position.

Olympic puzzle

Gecode model: olympic.cpp.

This is a Prolog benchmark problem.

Seesaw problem

Gecode model: stuckey_seesaw.cpp.

From Marriott & Stuckey "Programming with Constraints", page 257: Balancing on a seesaw.

Fractions problem

Gecode model: olympic.cpp.

This is another Prolog benchmark problem.

Killer Sudoku

Gecode model: killer_sudoku.cpp.

Killer Sudoku is yet another grid puzzle. This model solve the example shown at the Wikipedia page.

Kakuro

Gecode model: kakuro.cpp.

Kakuro is yet another grid puzzle. This model solve the example shown at the Wikipedia page.

KenKen

Gecode model: kenken2.cpp.

KenKen is yet another grid puzzle. This model solve the example shown at the Wikipedia page.

A Round of Golf (Dell Logic Puzzles)

Gecode model: a_round_of_golf.cpp.

Abbot's Puzzle

Gecode model: abbots_puzzle.cpp.

Abbot's puzzle ("Amusements in Mathematics, Dudeney", number 110)

Added Corner

Gecode model: added_corner.cpp.

Arch Friends (Dell Logic Puzzles)

Gecode model: arch_friends.cpp.

Babysitting (Dell Logic Puzzles)

Gecode model: babysittning.cpp.

Breaking News (Dell Logic Puzzles)

Gecode model: breaking_news.cpp.

Four Islands (Dell Logic Puzzles)

Gecode model: four_islands.cpp.

Lecture Series (Dell Logic Puzzles)

Gecode model: lecture_series.cpp.

Tunapalooza (Dell Logic Puzzles)

Gecode model: tunapalooza.cpp.

Five brigands problem

Gecode model: five_brigands.cpp.

The Five Brigands problem from Dudeney: "Amusements in Mathematics" (number 133)

Circling Squares

Gecode model: circling_squares.cpp.

From Dudeney: "Amusements in Mathematics".

Mama's Age

Gecode model: circling_squares.cpp.

From Dudeney: "Amusements in Mathematics", number 40.

Mrs Timpkin's Age

Gecode model: timpkin.cpp.

From Dudeney: "Amusements in Mathematics", number 43.

Torn Number

Gecode model: torn_number.cpp.

From Dudeney: "Amusements in Mathematics", number 113.

Twin letters problem

Gecode model: twin_letters.cpp.

Monks and doors problem

Gecode model: monks_and_doors.cpp.

Contracting Costs

Gecode model: contracting_costs.cpp.

From "Mathematical Puzzles of Sam Loyd, Volume 2", number 20.

General Store

Gecode model: general_store.cpp.

From "Mathematical Puzzles of Sam Loyd, Volume 2", number 30.

Crypta (cryptarithmetic puzzle)

Gecode model: curious_set_of_integers.cpp.

Prolog benchmark problem.

All interval

Gecode model: all_interval.cpp.

Note: This is a fairly true port from the MiniZinc model all_interval.mzn, and it's not very fast. A faster implementation is in the Gecode distribution: all-interval.

Devil's Word

Gecode model: devils_word.cpp.

Translate each character in a word to ASCII value and then try to sum its values (either positive or negative) to a total. Compare with my CGI program Devil's Word

Dinner problem

Gecode model: dinner.cpp.

A very simple dinner problem.

Music Men

Gecode model: music_men.cpp.

Yet another logical puzzle.

Number of days problem

Gecode model: number_of_days.cpp.

Problem from Nathan Brixius' blog post Solving a Knapsack problem with Solver Foundation and LINQ.

Pigeon hole problem

Gecode model: pigeon_hole.cpp.

Pandigital numbers

Gecode model: pandigital_numbers.cpp.

Seven-11 problem

Gecode model: seven11.cpp.

Ski assignment problem

Gecode model: ski_assignment.cpp.

Smuggler's knapsack problem

Gecode model: smuggler_knapsack.cpp.

Smuggler's knapsack problem from Marriott & Stuckey "Programming with constraints", page 101f, 115f

Square root of WONDERFUL

Gecode model: square_root_of_wonderful.cpp.

From Martin Gardner.

Place number puzzle

Gecode model: place_number_puzzle.cpp.

Post office problem

Gecode model: post_office_problem2.cpp.

Problem from Wayne Winston's "Operations Research: Applications and Algorithms": minimizing the number of workers at a post office.

Pythagoras

Gecode model: pythagoras.cpp.

Generating solutions of A^2 + B^2 = C^2 for A,B,C 0..Int::Limits::max.

Rabbits problem

Gecode model: rabbits.cpp.

A very simple linear problem from Pascal Van Hentenryck: "The OPL Optimization Programming Language", page 9.

Remainders problem

Gecode model: remainders.cpp.

From Kordemsky.

Safe cracking problem

Gecode model: safe_cracking.cpp.

Miss Manners' seating problem

Gecode model: miss_manners.cpp.

Problem formulation from CP-standards:
The "Miss Manners" problem is a notorious benchmark for rule engines. The problem is to find an acceptable seating arrangement for guests at a dinner party. It should match people with the same hobbies (at least one), and to seat everyone next to a member of the opposite sex.
I'm somewhat reluctant to publish this model: Although the solution is shown after just a second, it takes "forever" to prove that it is the best. Well, maybe it just a question of correct labeling, but I have found none efficient.

Changes of my Gecode models for version 3.4.0

See Gecode version 3.4 released for a description of things that was changed in Gecode version 3.4.0.

One major change was replacement of tt, imp, eqv, ~ for logical implication, equivalence, and reification to a neater syntax, as well as post has been replaced with rel and expr.

For example, in alldifferent_except_0.cpp (decomposition of the global constraint all different except 0), this code segment
post(space,
     tt(imp(x[i] != c && x[j] != c, // =>
     x[i] != x[j])),
     icl
     );
is now written
rel(space,
   (x[i] != c && x[j] != c) >> (x[i] != x[j]),
   icl
);
This is a more direct syntax which I like very much. Since I'm a lazy person, I love this kind of syntactic sugar.

Another example is from who_killed_agatha2.cpp. This older code segment:
 post(*this, 
      tt(
        imp(hates_m2(i, agatha) == 1, 
            hates_m2(i, butler) == 1)), 
        opt.icl()
     ); 
is now written
 rel(*this, 
        (hates_m2(i, agatha) == 1) >> 
        (hates_m2(i, butler) == 1), 
        opt.icl()); 
Here are all the changed models, which are available at my Gecode page. Many of them required just a simple change of post() to rel(); then there is no special comment below.

A comment: I will very soon also blog about a couple (about 100) new Gecode models that also - as much as possible - use the new syntax.

Gecode version 3.4 released

Version 3.4 of Gecode has been released. It can be downloaded here.

This version has quite a few changes. My favorites are
  • the extended "syntactic sugar" for rel and expr
  • "Modeling and Programming with Gecode" which has been extended with many sections and chapters, for example quite a few case studies.
Very soon after this blog post, I will also publish two posts related to this new Gecode version: Here are the Changes:
Changes in Version 3.4.0 (2010-07-26)

This release includes: considerably improved support for posting expressions and relations (also including set and full arithmetic expressions); other improvements for modeling (array initialization and element addition to arrays); state-of-the-art unary and cumulative scheduling propagators (including optional and flexible tasks); major cleanups of the variable and view infrastructure (now also documented in MPG); cleanups of the examples; several other fixes and performance improvements.

This release is the first to be accompanied by a complete version of "Modeling and Programming in Gecode" which has been extended by many new case studies and parts on programming search engines and variables.

  • Kernel
    • Additions
      • Added LocalObject and LocalHandle classes that can be used for space-allocated objects that are shared within a space, for example among several propagators or propagators and branchers. (minor)
    • Other changes
      • The support for dynamically resizing variable arrays has been removed (it was buggy and inefficient). Instead, all argument arrays now support adding elements using operator<<. In addition, all arrays now support concatenation using operator+ and slicing, and variable arrays, view arrays, and variable argument arrays include a test whether all variables are assigned. (major)
    • Bug fixes
      • Posting a propagator in a failed space could make the space non-failed again. (minor)
  • Finite domain integers
    • Additions
      • You can now construct IntArgs from an STL vector, an IntSharedArray, or using simple comprehensions. (minor)
    • Other changes
      • The argument arrays now have constructors that create new variables. (minor)
      • IntArgs with simple sequences of values can now be created using the IntArgs::create static member function. (minor)
    • Performance improvements
      • Optimized element propagator, expect a speed up of around 35-50% in most cases. (minor)
  • Finite integer sets
    • Other changes
      • The argument arrays now have constructors that create new variables. (minor)
    • Bug fixes
      • Fixed the include and exclude tell operations of set variables so that they work with empty ranges. (minor)
  • Scheduling constraints
    • Additions
      • Added scheduling constraints for tasks with flexible duration (for both unary and cumulative resources), and made all scheduling propagators deal correctly with zero length tasks. (major)
      • Added propagators for cumulative scheduling. (major)
  • Minimal modeling support
    • Additions
      • The minimodel library now provides convenient post functions for set constraints. (major)
    • Other changes
      • The Matrix class now supports const operations and has an output operator. (minor)
      • Linear expressions can now contain non-linear parts, such as multiplications or divisions, or set expressions such as cardinality. (major)
      • The minimodel post functions have been split into two functions, rel and expr. While rel posts a constraint, expr returns a new variable constrained to the given expression. This change makes it possible to get rid of the reification operator (~) as well as the tt and ff functions, which were previously needed to distinguish between relations and expressions. Boolean equivalence and implication can now be expressed using operators (==,<<,>>). (major)
      • Array slices can now be empty. (minor)
    • Bug fixes
      • Fixed a bug in minimodel, which could crash when using zero coefficients. (minor, thanks to Håkan Kjellerstrand)
    • Performance improvements
      • Posting linear expressions performs more aggressive optimizations for assigned variables. (minor)
      • Arithmetic modeling functions now try to avoid creating new variables and posting propagators for common cases. (minor)
  • Script commandline driver
    • Other changes
      • The driver now catches SIGINT (i.e., pressing Ctrl-C) and stops the search properly, printing statistics up to the point where it stopped. (minor)
      • Running a script in time mode stops all iterations and samples immediately if a single run reaches a limit (eases benchmarks with timeouts). (minor)
  • Example scripts
    • Additions
      • New custom branching for the BACP example using a custom value selection. (minor)
    • Removals
      • Removed stress tests, the real examples are much more stressful, actually! (minor)
    • Other changes
      • The Nonogram example now uses AFC as the default branching and includes some more instances. (minor)
      • Take advantage of the better modeling support for the Balanced incomplete block design (BIBD), Golomb ruler, Kakuro, Black Hole, and Warehouse examples (nothing but dusting off examples that have been around for ages). (minor)
  • Gist
    • Other changes
      • If an inspector throws an exception, an error message is printed indicating which inspector caused the problem. Previously, Gist would crash with a Qt error that was difficult to trace. (minor)
    • Bug fixes
      • Fixed bug in Gist where signals were sent across threads, which makes Qt crash in certain situations on some platforms. (minor)
      • Fixed bug in interactive search where every move in the tree required recomputation. (minor, thanks to David Zaremby)
  • Gecode/FlatZinc
    • Bug fixes
      • Boolean relations were incorrect on assigned arguments. (minor)
      • Fixed garbage collection of variables that are not printed. The bug lead to variables being mixed up in the output. (minor)
  • General
    • Removals
      • Variables do not have init functions any longer as they are not needed, see MPG for discussion. (minor)
    • Other changes
      • Completely cleaned up variables and views, drastically saving code. (major)
      • The configure script now checks for qmake-qt4 and moc-qt4, which are used on some Linux systems to distinguish between Qt3 and Qt4. (minor)
      • The build system now supports Visual C++ 2010. (minor)

July 22, 2010

Minizinc version 1.1.5 released

Version 1.1.5 of MiniZinc has been released. It can be downloaded here.

From the NEWS:

Bugs fixed in this release:

* We have fixed a number of problems that caused stack overflows in mzn2fzn.

* The FlatZinc interpreter's MIP backend no longer reports "unknown" for
satisfaction problems.

July 20, 2010

Minizinc version 1.1.4 released

MiniZinc version 1.1.4 has been released. It can be downloaded here.

From the NEWS:

Changes in this release:

* We have added a library of global constraint definitions and FlatZinc built-in redefinitions suitable for use with LP/MIP solvers; both are in the "linear" directory of the MiniZinc library.

Bugs fixed in this release:

* Some performance issues with mzn2fzn that occurred when flattening models that generate and traverse large arrays have been fixed.

* An omission that caused mzn2fzn not to recognise the MiniZinc built-in function round/1 has been corrected.

* A bug in flatzinc that caused the MIP backend to abort when the model instance contained an unused set parameter has been fixed. [Bug #134]

* A bug in mzn2fzn that caused it not to place domain constraints on the FlatZinc variables generated for an array of variables introduced via a let expression has been fixed. [Bug #133]

* The implementation of the div propagator in flatzinc's FD backend has been modified to avoid potentially long fixpoint computations.

July 18, 2010

Some new MiniZinc models

Here are some new MiniZinc models. Some are completely new - or previously unannounced - but there are also some which has been implemented in some other constraint programming system before.

New models

Here are some new - or at least previously not announced - models:

Latin square card puzzle

latin_square_card_puzzle.mzn: Latin square card puzzle

I found this problem in Mario Livio's nice PopSci book about the development of group theory The Equation that couldn't be solved, page 22:
... Incidentally, you may get a kick out of solving this eighteenth century card puzzle: Arrange all the jacks, queens, kings, and aces from a deck of cards in a square so that no suit or value would appear twice in any row, column, or the two main diagonals.
My general approach is to use integers of the following form. n is the size of the matrix (here 4) and m is the number we use for modulo operation (here 10). These values are calculated automatically by the model depending on n.
 % values: i mod 10 
  0, 1, 2, 3,  % suite 1: 0 div 10
 10,11,12,13,  % suite 2: 1 div 10
 20,21,22,23,  % suite 3: 2 div 10
 30,31,32,33   % suite 4: 3 div 10
What then want that the values divided by 10 (the suites) should be different in each row, column, and diagonals, and also the values by modulo 10 (the values) is different in each row, column, and diagonals.

With the symmetry breaking constraint that the value 0 must be in the upper leftmost cell, there are 72 solutions for n = 4. Here is one of them:
 0 33 22 11
21 12  3 30
13 20 31  2
32  1 10 23
Note: There are solutions for n = 4 and n = 5 but not for n = 6. The n = 6 problem is the same as Euler's 36 officer's problem, which thus is not solvable. Also see MathWorld.

Investment problem

This problem is from ORMM (Operations Research Models and Methods):
A portfolio manager with a fixed budget of $100 million is considering the eight investment opportunities shown in Table 1. The manager must choose an investment level for each alternative ranging from $0 to $40 million. Although an acceptable investment may assume any value within the range, we discretize the permissible allocations to intervals of $10 million to facilitate the modeling. This restriction is important to what follows. For convenience we define a unit of investment to be $10 million. In these terms, the budget is 10 and the amounts to invest are the integers in the range from 0 to 4.
Here are two implementations:

Arg max

argmax.mzn

argmax/argmin predicate
  • argmax_ge(pos, x)
    pos is the index x for the maximum value(s). There can be many maximum values.
  • argmax_gt(pos, x)
    pos is the index x for the maximum value. There can be only one maximum value.
  • argmin_le(pos, x)
    pos is the index x for the minimum value(s). There can be many minimum values.
  • argmin_lt(pos, x)
    pos is the index x for the minimum value. There can be only one maximum value.

Permutation number

permutation_number.mzn

A permutation number is the number of transpositions in a permutation, see Wikipedia Permutation.

Sicherman dice

sicherman_dice.mzn

From Wikipedia Sicherman_dice:
Sicherman dice are the only pair of 6-sided dice which are not normal dice, bear only positive integers, and have the same probability distribution for the sum as normal dice.

The faces on the dice are numbered 1, 2, 2, 3, 3, 4 and 1, 3, 4, 5, 6, 8.
I read about this problem in a book/column by Martin Gardner long time ago, and got inspired to model it now by the recent WolframBlog post Sicherman Dice

Here is the vital part of the code:
array[2..12] of int: standard_dist = 
       array1d(2..12, [1,2,3,4,5,6,5,4,3,2,1]);
% the two dice
array[1..n] of var 1..m: x1 :: is_output;
array[1..n] of var 1..m: x2 :: is_output;
constraint
forall(k in 2..12) (
  standard_dist[k] = 
    sum(i,j in 1..n) ( 
       bool2int(x1[i]+x2[j] == k)
    )
)
% symmetry breaking
/\ increasing(x1) 
/\ increasing(x2)

/\ % x1 is less or equal to x2
forall(i in 1..n) (
   x1[i] <= x2[i]
)
% /\ lex_lesseq(x1, x2)
This model gets the two different solutions, first the standard dice and then the Sicherman dice:
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]

--

[1, 2, 2, 3, 3, 4]
[1, 3, 4, 5, 6, 8]
Extra: If we also allow that 0 (zero) is a valid value then the following two solutions are also shown. The only thing we have to do is to change the domains of x1 and x2:
% the two dice
array[1..n] of var 0..m: x1 :: is_output;
array[1..n] of var 0..m: x2 :: is_output;
Here here are the two new solutions:
[0, 1, 1, 2, 2, 3]);
[2, 4, 5, 6, 7, 9]);

--

[0, 1, 2, 3, 4, 5]);
[2, 3, 4, 5, 6, 7]);
These two extra cases are mentioned in MathWorld SichermanDice.

Translations of other models

The following MiniZinc models is ports from models written in at least one other constraint programming system before, mostly Comet:

July 16, 2010

Helmut Simonis' blog: Constraint Applications Blog

Helmut Simonis has started to blog: Constraint Applications Blog - Lots of Constraint Applications. This is great news and it will be very interesting to follow his writings.

He was kind enough to email me and also described his intentions with the blog:


I will look at constraint applications (in the wider sense).

...

At the moment, I'm talking about projects I have been involved in myself, but I image I will run out of material quickly, so that I will also consider papers written on applications by other authors, to abstract and classify them. The idea is to develop a collection of applications in different fields, where one can check what has been done by whom, and where to find more information.

He has been quite busy the last weeks and blogged a lot about of his projects. Here are some of the posts so far:


July 06, 2010

Lightweight Dynamic Symmetry Breaking (LDSB) for Gecode

Christopher Mears just announced on the Gecode mailing list that he has released (a somewhat experimental version of) Lightweight Dynamic Symmetry Breaking (LDSB) library for Gecode (version 3.3.1).

In the announce mail, Mears writes:
The main strength of LDSB is that it allows symmetry breaking to 
be added very simply to a model.  Here is an example:
// ...
IntVarArray xs;
ExampleModel() : xs(*this, 4, 0, 3)
{
    distinct(*this, xs);

    // Symmetry breaking starts here...
    Symmetries s(1);
    s[0] = values_interchange(*this, xs);
    // ... and ends here.

    branch(*this, xs, INT_VAR_NONE, INT_VAL_MIN, s);
}
// ...
There are also a lot of examples how to use LDSB in the package.

The reference for LDSB is C. Mears, M. Garcia de la Banda, B. Demoen, M. Wallace. Lightweight Dynamic Symmetry Breaking. Faculty of Information Technology, Monash University, No. 2010/254, 2010. However, I have not found the paper online.

LDSB was first written for ECLiPSe (and is included in recent releases); see the ECLiPSe documentation for more details about the ECLiPSe LDSB package.