" /> My Constraint Programming Blog: February 2012 Archives

« January 2012 | Main | March 2012 »

February 27, 2012

Gecode version 3.7.2 released

Gecode version 3.7.2 has been released. It can be downloaded here.

From the Changelog:
Changes in Version 3.7.2 (2012-02-27)

This release fixes several small bugs.

  • Kernel
    • Additions
      • Added Archive operators for floats and doubles. (minor)
  • Finite domain integers
    • Other changes
      • Throw exception of type OutOfLimits instead of Exception when numerical arguments to sequence constraint are out of range. (minor)
    • Bug fixes
      • Added missing pruning to cumulative edge finding propagator. (minor, thanks to Joseph Scott)
      • Fixed sorted constraint to accept zero-length arrays. (minor, thanks to Kish Shen)
      • Added some missing propagation when posting a channel constraint between an array of Boolean variables and an integer variable. (minor, thanks to Kish Shen)
    • Performance improvements
      • Posting a reified dom constraint on IntVars with an assigned control variable does not create propagators any more, but updates the domain immediately. (minor)
  • Finite integer sets
    • Bug fixes
      • The element constraint with SOT_UNION and IntSetArgs reported subsumption too early, resulting in incorrect propagation. (major, thanks to Denys Duchier)
  • Minimal modeling support
    • Bug fixes
      • The BoolExpr default constructor did not properly initialize its members, causing crashes. (minor)
  • Script commandline driver
    • Bug fixes
      • Fixed rounding for printing the runtime (for example, 1:60:56.157 could be printed...). (minor, thanks to Serge Le Huitouze)
      • Fixed time output for times with zero minutes but nonzero hours. (minor, thanks to Jan Kelbel)
  • Gecode/FlatZinc
    • Bug fixes
      • Export RTTI symbols for the FlatZinc AST so that it can be used by client code. (minor)
      • Do not crash when encountering undefined identifier as constraint argument. (minor, thanks to Nicholas Tung)
  • General
    • Additions
      • Gecode now compiles on NetBSD. (minor, thanks to Adam Russell)
      • Added a macro GECODE_VERSION_NUMBER that is defined as x*1000000+y*100+z for Gecode version x.y.z. (minor, thanks to Denys Duchier)

February 08, 2012

G12 MiniZinc version 1.4.3 released

G12 MiniZinc version 1.4.3 has been released. Download here.

From the NEWS
G12 MiniZinc Distribution 1.4.3
-------------------------------

Changes in this release:

* We have added more redefinitions of FlatZinc built-ins to the "linear" MiniZinc library specialisation. This allows a wider range of MiniZinc models to solved using LP/MIP solvers.

* We have added decompositions of lex_less/2, lex_lesseq/2, lex_greater/2 and lex_greatereq/2 for Boolean arrays.

Bugs fixed in this release:

* We have fixed a bug in mzn2fzn that caused it to generate invalid FlatZinc for some var array lookups. [Bug #312]

February 05, 2012

A first look at Google or-tools C# interface

In early January Laurent Perron announced that or-tools now supports .NET (C#). A few minutes after I read that, I (and probably many others) wrote to him and asked when there will be a support of Mono (.NET support on Linux, Mac etc). After some week Laurent mailed me to announce that he and Mark Farkas had fixed Mono support as well. Great work!

So, this is what I have done the last weeks: Learning more about C# and modeled some models in or-tools/C#. My models are at my or-tools/C# page, and most of them has been pushed to the project's SVN: code.google.com/p/or-tools/source/browse/trunk/csharp/.

This blog post can be seen as the third part in the "First looks" at Google or-tools tools, where the previous two where A first look at Google CP Solver/Python (Google or-tools) and A first look at Google or-tools' Java interface. Since much of the things in or-tools/C# works the same as for Python and Java I will here mention more about of the differences from these versions.

or-tools/C#

Google or-tools is Google's Operations Research Tools developed at Google and is an open source (though committing and contribution require special handling). The kernel of the solvers is written in C++, and it now supports Constraint Programming (which is - of course - my main interest here) and Mathematical Programming with support for the external solvers Gurubi, GLPK, CBC, and SCIP/Zib Optimization Suite, and modeling interface for C++, Python, Java, and now .NET/C#.

Syntactic sugar - a first example

The first version of or-tools/C# (.NET) was released about January 19, but didn't have much syntactic sugar; instead the models looked very much like the Java models which was kind of lucky for me since it made the porting of these models quite easy. However, after a while Laurent added quite a few shortcuts (i.e. syntactic sugar) which made the modeling much easier. During the following weeks, Laurent added more sugaring, some probably after my complaint, suggestions, or - in some case - confusion.

For example: Here is the first version of least_diff.cs (Least Diff is a simple alphametic optimization problem where the object is to minimize the difference ABCDEF-FGHIJ where A..J is distinct digits). You can see the SVN history of this model here.
using System;
using Google.OrTools.ConstraintSolver;

public class LeastDiff
{
  private static void Solve()
  {
    Solver solver = new Solver("LeastDiff");

    IntVar A = solver.MakeIntVar(0, 9, "A");
    IntVar B = solver.MakeIntVar(0, 9, "B");
    IntVar C = solver.MakeIntVar(0, 9, "C");
    IntVar D = solver.MakeIntVar(0, 9, "D");
    IntVar E = solver.MakeIntVar(0, 9, "E");
    IntVar F = solver.MakeIntVar(0, 9, "F");
    IntVar G = solver.MakeIntVar(0, 9, "G");
    IntVar H = solver.MakeIntVar(0, 9, "H");
    IntVar I = solver.MakeIntVar(0, 9, "I");
    IntVar J = solver.MakeIntVar(0, 9, "J");

    IntVar[] all = new IntVar[] {A,B,C,D,E,F,G,H,I,J};
    int[] coeffs = {10000,1000,100,10,1};
    IntVar x =
        solver.MakeScalProd(new IntVar[]{A,B,C,D,E}, coeffs).Var();
    IntVar y =
        solver.MakeScalProd(new IntVar[]{F,G,H,I,J}, coeffs).Var();
    IntVar diff =
        solver.MakeDifference(x,y).VarWithName("diff");

    solver.Add(solver.MakeAllDifferent(all));
    solver.Add(A > 0);
    solver.Add(F > 0);
    solver.Add(diff > 0);

    OptimizeVar obj = solver.MakeMinimize(diff, 1);

    DecisionBuilder db = solver.MakePhase(all,
                                          Solver.CHOOSE_PATH,
                                          Solver.ASSIGN_MIN_VALUE);

    solver.NewSearch(db, obj);
    while (solver.NextSolution()) {
      Console.WriteLine("{0} - {1} = {2}  ({3}",
           x.Value(), y.Value(), diff.Value(), diff.ToString());
    }

    Console.WriteLine("\nSolutions: {0}", solver.Solutions());
    Console.WriteLine("WallTime: {0}ms", solver.WallTime());
    Console.WriteLine("Failures: {0}", solver.Failures());
    Console.WriteLine("Branches: {0} ", solver.Branches());

    solver.EndSearch();

  }

  public static void Main(String[] args)
  {
    Solve();
  }
}
After Laurent added some syntactic sugar, the constraint and solve part looks like this which in my book is better and easier to work with: all the Make* constructs are removed. Also, equality (==) was sugared after a while but it's not shown here.
// ....
IntVar x = new IntVar[]{A,B,C,D,E}.ScalProd(coeffs).Var();
IntVar y = new IntVar[]{F,G,H,I,J}.ScalProd(coeffs).Var();
IntVar diff = (x - y).VarWithName("diff");

solver.Add(all.AllDifferent());
solver.Add(A > 0);
solver.Add(F > 0);
solver.Add(diff > 0);

OptimizeVar obj = diff.Minimize(1);

DecisionBuilder db = solver.MakePhase(all,
                                      Solver.CHOOSE_PATH,
                                      Solver.ASSIGN_MIN_VALUE);
solver.NewSearch(db, obj);
Here's how to compile and run this model with Mono on a Linux box.
$ export MONO_PATH=$MONO_PATH:/path-to-or-tools/
$ mono-csc /r:Google.OrTools.ConstraintSolver.dll least_diff.cs
$ ./least_diff.exe
....
50123 - 49876 = 247  (diff(247)

Solutions: 30
WallTime: 27ms
Failures: 20
Branches: 83 

Performance comparing to Python and Java versions

Since the Python, Java, and C# models use the same engine there is very little difference between of the performance of models written in these languages, at least when using the same approach and the same heuristics.

As an example, we can continue with the comparison in A first look at Google or-tools' Java interface where the Python and Java versions of a N-queens problem where benchmarked. The results for (the first solution of) N=8, 100, 1000, and 10000 using the C# model nqueens.cs is the same as for the other two implementations:
     N    Failures       Branches      Wall time Required
                                                 memory
  -------------------------------------------------------
     8      3               9            5ms
   100     12             120           10ms 
  1000      0             996          470ms
 10000      0            9999        78923ms     2.1Gb
This is exactly the same result as for Python and Java. Again, this is not surpising since they all use the same underlying solver engine. Comparing Java and C# (using Mono) it seems that the Mono version is slightly faster both in compiling and the time for upstart, though this has not been tested systematic.

The (interesting part of the) model nqueens.cs is:
IntVar[] q = solver.MakeIntVarArray(n, 0, n-1, "q");

solver.Add(q.AllDifferent());

IntVar[] q1 = new IntVar[n];
IntVar[] q2 = new IntVar[n];
for(int i = 0; i < n; i++) {
  q1[i] = (q[i] + i).Var();
  q2[i] = (q[i] - i).Var();
}
solver.Add(q1.AllDifferent());
solver.Add(q2.AllDifferent());

DecisionBuilder db = solver.MakePhase(q,
           Solver.CHOOSE_MIN_SIZE_LOWEST_MAX,
           Solver.ASSIGN_CENTER_VALUE);

LINQ

The nqueens model shown above is a very straightforward implementation, but the interesting part of C# is that we can use LINQ to do array handling in another way using "query comprehensions" (array comprehensions). Although it was one of my objects to learn more about LINQ, I'm not sure if this is better (= more clear) in this particular case. Anyway, here is one way of stating the constraints using LINQ:
solver.Add(q.AllDifferent());
solver.Add((from i in Enumerable.Range(0, n)
            select (q[i] + i).Var()).ToArray().AllDifferent());
solver.Add((from i in Enumerable.Range(0, n)
            select (q[i] - i).Var()).ToArray().AllDifferent());
I think that LINQ shines more in hidato_table.cs (a port of Laurent Perron's Python version using a Table/AllowedAssignments constraint):
  public static int[,] BuildPairs(int rows, int cols)
  {
    int[] ix = {-1, 0, 1};
    var result_tmp = (from x in Enumerable.Range(0, rows)
                      from y in Enumerable.Range(0, cols)
                      from dx in ix
                      from dy in ix
                      where
                      x + dx >= 0 &&
                      x + dx < rows &&
                      y + dy >= 0 &&
                      y + dy < cols &&
                      (dx != 0 || dy != 0)
                   select new int[] {x * cols + y, (x + dx) * cols + (y + dy)}
                      ).ToArray();

    // Convert to len x 2 matrix
    // ....


    return result;
  }
It's not as nice as the Python version, since we must also convert to an int[,] matrix because AllowedAssignments requires this type, but still. (And - of course - there might be another and even simpler version of this that don't require this conversion....)

A side note: one can see how old my C# models are in the use of LINQ, since in later models I tend to use LINQ (and foreach) much more than in earlier models. Also, the models use a quite restricted part of LINQ: almost only from, select, and sometimes where, but not much of the more fancy stuff that LINQ supports. This is because I use it mostly as a layers of handling IntVar's where grouping etc is not appropriate (as I have understood it with some experiments).

MakeIntVarMatrix

One thing that is quite nice - and a sign of Laurent's willingness to help lazy programmers such as myself - is MakeIntVarMatrix. Here is the way one had to do in earlier C#-models to declare an IntVars matrix (i.e. matrix of decision variables) as well as creating an 1D array (x_flat) to be used for the search.
IntVar[,] x = new IntVar[r,c];
IntVar[] x_flat = new IntVar[r*c];
for(int i = 0; i < r; i++) {
  for(int j = 0; j < c; j++) {
    x[i,j] = solver.MakeIntVar(0, 1);
    x_flat[i*c+j] = x[i,j];
  }
} 	
(Note: this is still the way one has to make matrices of decision variables in Python and Java.) However, now one can use these much simpler constructs in C#:
IntVar[,] x = solver.MakeIntVarMatrix(r, c, 0, 1, "x");
IntVar[] x_flat = x.Flatten();
Very handy!

Element

It would not be a complete First look-report if there wasn't any comment about the support of Element in the tested CP system (see for example Learning constraint programming - part II: Modeling with the Element constraint). In one way, how Element is supported can be seen as a proxy of the "expressiveness" of a CP system and its host language. (And this expressiveness is quite important, at least when learning a CP system or perhaps learning CP from the start.)

As with other constraints, Laurent simplified Element after a while. The Who killed Agatha problem is often a good test how easy it is to use Element in a system. The C# model who_killed_agatha.cs has a description of the problem statements.

One of the constraint in this model can be expressed as simple as this in - say - MiniZinc or Comet where hates is a matrix if IntVar, and both the_killer and the_victim are IntVar.
 % MiniZinc/Comet code
 hates[the_killer, the_victim] == 1
This constraint was at first expressed in C# as the code below, which is a rather faithful port from the Java version (WhoKilledAgatha.java):
solver.Add(
   solver.MakeEquality(
      solver.MakeElement(
            hates_flat,
            solver.MakeSum(
            solver.MakeProd(the_killer, n).Var(),
   the_victim).Var()).Var(), 1));
After Laurent's sugaring it can now be stated as the much simpler:
solver.Add(hates_flat.Element(the_killer * n + the_victim) == 1);
This is perhaps as good as one can get when it's not possible to state the constraints in the matrix direct by overloading index access ([,]) of a matrix in the host language. Almost all CP systems embedded in a host programming language requires this kind of handling. (Compare with Gecode that supports constraints directly with the matrix, see Gecode: Modeling with Element for matrices -- revisited; Christian Schulte fixed this support after my complaints during a CP lecture...)

Decompositions

Another thing that it's nice to have in a CP system it to be able to write decompositions that can be used similar as the built-in constraints where - again - simplified syntax helps much. Here is my standard decomposition of the channeling between an IntVar array representing digits and and IntVar variable representing the numbers with these digits (see below for a LINQed version)
private static Constraint ToNum(IntVar[] a, IntVar num, int bbase) {
  int len = a.Length;
  IntVar[] tmp = new IntVar[len];
  for(int i = 0; i < len; i++) {
    tmp[i] = (a[i]*(int)Math.Pow(bbase,(len-i-1))).Var();
  }
  return tmp.Sum() == num;
}
It can now be used much as any constraint, as in pandigital_numbers.cs (yet another alphametic problem). The object is to find all possible multiplications of the form term1 * term2 = product which use all digits. Here we see how the first term (called num1) is calculated:
IntVar[] x = solver.MakeIntVarArray(x_len, start, max_d, "x");
// ...
// First term
solver.Add(ToNum((from i in Enumerable.Range(0, len1)
                  select x[i].Var()).ToArray(),
                  num1, 
                  bbase));
This is also another example how LINQ can simplify the model.

In to_num.cs its use is more direct:
IntVar[] x = solver.MakeIntVarArray(n, 0, bbase - 1, "x");
IntVar num = solver.MakeIntVar(0, (int)Math.Pow(bbase, n) - 1, "num");
solver.Add(x.AllDifferent());
solver.Add(ToNum(x, num, bbase));


As an afterthought: The constraint ToNum could be written like this instead using LINQ:
// ...
int len = a.Length;
return (from i in Enumerable.Range(0, len)
        select (a[i]*(int)Math.Pow(bbase,len-i-1)).Var()
        ).ToArray().Sum() == num;

Mathematical programming

There is also support for Mathematical programming in or-tools (there is also much support for linear programming that I haven't tested much in my earlier or-tools projects). I have just tested this with three simple models which solves almost the same problem using different approaches: then Volsay problem (from OPL).
  • volsay.cs: Volsay LP problem (using "Natural API")
  • volsay2.cs: Volsay LP problem, using arrays for representing the data
  • volsay3.cs: Volsay LP problem, arrays/matrices with components added.
The first model (volsay.cs) looks like this using the "Natural API" for stating the constraints:
// ...
Solver solver = new Solver("Volsay",
                               Solver.CLP_LINEAR_PROGRAMMING);

Variable Gas = solver.MakeNumVar(0, 100000, "Gas");
Variable Chloride = solver.MakeNumVar(0, 100000, "Cloride");
Constraint c1 = solver.Add(Gas + Chloride <= 50);
Constraint c2 = solver.Add(3 * Gas + 4 * Chloride <= 180);

solver.Maximize(40 * Gas + 50 * Chloride);
int resultStatus = solver.Solve();
if (resultStatus != Solver.OPTIMAL) {
  Console.WriteLine("The problem don't have an optimal solution.");
  return;
}
Console.WriteLine("Objective: {0}", solver.ObjectiveValue());
Console.WriteLine("Gas      : {0} ReducedCost: {1}", 
                  Gas.SolutionValue(), 
                  Gas.ReducedCost());
// ...

Search, labeling

Searching and labeling are very much the same in C# as in Python and Java. As can be seen in the Least Diff model above, the C# interface use a simplified way of stating the optimization variable:
OptimizeVar obj = solver.MakeMinimize(diff, 1);
But otherwise it was no surprises compared to the Python and Java models.

Not tested (yet)

There are some things I have yet to test for C#, especially Nonogram using DefaultSearch, where the Python version was quite fast after some tweaking: Google CP Solver: A much faster Nonogram solver using DefaultSearch. Perhaps I will port this to C# as well. Also, there are certain MIP models in or-tools/Python that perhaps will be converted to C#.

Summary

I like this .NET/C# interface to or-tools, much because there is more syntactic sugar than in Java version making it easier to write models, especially when prototyping models; though with Python, been the VHLL language it, is can be even easier. It was quite easy to port from my earlier Java and Python models, especially from the Java models since Java and C# are very similar on the host language level and they use almost exactly the same way of stating the constraint API. Though it took some more time to LINQ'ing these models.

There where very few models where I have any real problems porting from Python/Java, though I had to search for certain things, for example the best way of converting matrices written in Java/Python to C#'s matrices; often it required a change to jagged arrays especially when using Element on a row/column.

When writing models in C# for or-tools I found extremely few bugs, which is a sign of the stability of the support for external programming languages in or-tools.

Also, this was my first serious project to use Mono/C# and I'm impressed how smooth Mono is. This has given me a much better ground for developing more C# models/programs.

Also see

See earlier writings about or-tools, in the category google_cp_solver (which was the name I earlier used for or-tools), and my Google or-tools page which has quite a few Python, Java, and now C# models. My page Common constraint programming problems shows listings of the models that is implemented in other CP systems.

For more information about or-tools:

My or-tools/C# models

Here are all the (about 100) published or-tools/C# models so far. Most of them are ports from the Java or Python models, and most are also at the SVN: code.google.com/p/or-tools/source/browse/trunk/csharp/. Note that Laurent Perron has simplified and/or beautified some of these models. Thanks for this Laurent!