1.16k likes | 1.18k Views
This talk provides an introduction to Constraint Programming (CP), including key concepts and examples in modeling using MiniZinc. Learn how CP is used in industry and gain insights into solving combinatorial search and optimization problems. Join Håkan Kjellerstrand, a systems developer at Bokus, as he shares his expertise and passion for CP.
E N D
Constraint Programming: An introduction Håkan Kjellerstrand (hakank@gmail.com) http://hakank.org/ My Constraint Programming Blog: http://hakank.org/constraint_programming_blog/ My GitHub page: https://github.com/hakank/hakank/
Overview - What is Constraint Programming (CP) - why is it so fascinating? - Key concepts in CP - Examples of modelling, code in MiniZinc - Questions, please ask during the talk
Håkan Kjellerstrand - Systems developer at Bokus (http://www.bokus.com/) - Constraint Programming is a private interest - Built CP models, tested CP systems, and blogged/etc about CP since 2008 - Use CP for puzzles, explorations in mathematics/computer science , etc.
What is CP used for? In industry CP is used for, among many other things: - scheduling and resource allocation - staff rostering - complex configuration problems - packing problems - DNA sequencing - vehicle / transport routing - analysis of analog circuits - financial planning, investment management - ... In general: combinatorial search and optimization
What is CP? Some key concepts * Techniques * Modeling In this talk I will focus on the modeling part.
Main principle of CP – much simplified Key components: - DECISION VARIABLES - DOMAINS of the decision variables - CONSTRAINTS between the decision variables - All decision variables are declared with a domain (often finite domain), including arrays, matrices, etc. The CP solver loop: - The solver PROPAGATES the constraints and domains of the decision variables in the model until: * a FIXPOINT is reached (no changes in the domains) * or assign the variables in the search tree, perhaps via BACKTRACKING. - If a domain of a variable is empty then the assignment is illegal and the solver backtracks to test new assignments.
Time for some code! - MiniZinc Sites: - http://minizinc.org/ - http://hakank.org/minizinc/ (> 1100 public models) * One of the most high-level CP systems * Try a model and test with many solvers * About 30 different FlatZinc solvers with very different strengths * Drawback: not a general programming language
Sudoku 4x4 4 _ _ _ 3 1 _ _ _ _ 4 1 _ _ _ 2 Constraints: - all rows must have different digits - all columns must have different digits - all boxes (2x2) must have different digits Let's see how this can be stated in a CP system. 4 _ _ _ 3 1 _ _ _ _ 4 1 _ _ _ 2 Constraints: - all rows must have different digits - all columns must have different digits - all boxes (2x2) must have different digits Let's see how this can be stated in a CP system. 4 _ _ _ 3 1 _ _ _ _ 4 1 _ _ _ 2 Constraints: - all rows must have different digits - all columns must have different digits - all boxes (2x2) must have different digits Let's see how this can be stated in a CP system. 4 _ _ _ 3 1 _ _ _ _ 4 1 _ _ _ 2 Constraints: - all rows must have different digits - all columns must have different digits - all boxes (2x2) must have different digits Let's see how this can be stated in a CP system.
Sudoku 4x4 – MiniZinc code % Note: init of hints, search, and output missing % parameters (constants) int: r = 2; int: n = r*r; % i.e. 4 % decision variables array[1..n, 1..n] of var 1..n: x; % matrix constraint % i'th row forall(i in 1..n) (all_different([x[i,j] | j in 1..n])) /\ % j'th column forall(j in 1..n) (all_different([x[i,j] | i in 1..n])) /\ % the blocks forall(i in 0..r-1,j in 0..r-1) ( all_different([x[r,c] | r in i*r+1..i*r+r, c in j*r+1..j*r+r]) ) ;
Sudoku 4x4 – propagation 4 _ _ _ 3 1 _ _ _ _ 4 1 _ _ _ 2 Solution (unique) 4 2 1 3 3 1 2 4 2 3 4 1 1 4 3 2 How does a CP solver reach this solution?
Sudoku 4x4 – propagation example (simplified) Add DOMAINS (1..4) to all unknown variables. Hints are FIXED already. Now we will propagate the three alldifferent constraints: - all_different(ROW) - all_different(COLUMN) - all_different(BLOCK) This is a very simplified example. Real CP systems use more intelligent propagation. 4 123412341234 3 1 12341234 12341234 4 1 123412341234 2
Sudoku 4x4 – simple propagation example Cell (1,1): Fixed value (4). Cell (1,2): Reduce: - remove 4 (row, block) - remove 1 (column, block) - remove 3 (block) → Single value: 2 4 212341234 3 1 12341234 12341234 4 1 123412341234 2
Sudoku 4x4 – simple propagation example Cell (1,3): Reduce: - remove 4 (row, column) - remove 2 (row) → {1 3} 4 21 31234 3 1 12341234 12341234 4 1 123412341234 2
Sudoku 4x4 – simple propagation example Cell (1,4): Reduce: - remove 4 (row) - remove 1 (column) - remove 2 (column) → 3 Note: Here we don't go back to fix cell (1,3). Cell (2,1): fixed (3) Cell (2,2): fixed (1) 4 21 3 3 3 1 12341234 12341234 4 1 123412341234 2
Sudoku 4x4 – simple propagation example Cell (2,3): Reduce: - remove 3 (row) - remove 1 (row) - remove 4 (column) → 2 4 21 3 3 3 1 21234 12341234 4 1 123412341234 2
Sudoku 4x4 – simple propagation example Cell (2,4): Reduce: - remove 3 (row) - remove 1 (row, column) - remove 2 (row, column) → 4 4 21 3 3 3 1 2 4 12341234 4 1 123412341234 2
Sudoku 4x4 – simple propagation example Cell (3,1): Reduce: - remove 4 (row, column) - remove 1 (row) - remove 3 (column) → 2 4 21 3 3 3 1 2 4 21234 4 1 123412341234 2
Sudoku 4x4 – simple propagation example Cell (3,2): Reduce: - remove 1 (row, column, block) - remove 2 (row) - remove 4 (row) → 3 4 21 3 3 3 1 2 4 2 3 4 1 123412341234 2
Sudoku 4x4 – simple propagation example Cell (3,3): Fixed. Cell (3,4): Fixed. 4 21 3 3 3 1 2 4 2 3 41 123412341234 2
Sudoku 4x4 – simple propagation example Cell (4,1): Reduce - remove 2 (row) - remove 4 (column) - remove 3 (column) → 1 4 21 3 3 3 1 2 4 2 3 4 1 112341234 2
Sudoku 4x4 – simple propagation example Cell (4,2): Reduce - remove 1 (row) - remove 2 (row) - remove 3 (column) → 4 4 21 3 3 3 1 2 4 2 3 4 1 1 41234 2
Sudoku 4x4 – simple propagation example Cell (4,3): Reduce - remove 2 (row, block) - remove 4 (column, block) • - remove 1 (block) → 3 Cell (4,4): Fixed 2 Are we finished? No! There is still a variable/cell with no single assignment, i.e. Cell (1,3). 4 21 3 3 3 1 2 4 2 3 4 1 1 432
Sudoku 4x4 – simple propagation example Cell (1,3): Reduce - remove 3 (row, block) → 1 And now all variables has been assigned to a single value. 4 21 3 3 1 2 4 2 3 4 1 1 4 3 2
Sudoku 4x4 – simple propagation example … and we got a solution! It is unique – as a Sudoku should be. 4 2 1 3 3 1 2 4 2 3 4 1 1 4 3 2
Sudoku 4x4: Points to take home * Propagation and domain reduction is one of the key principles to CP. * CP solvers are more intelligent than this.
Another model: Minesweeper – Where are the bombs? Minesweeper – in this version – is a simple grid problem: ..2.3. 2..... ..24.3 1.34.. .....3 .3.3.. - Each number represents how many bombs there are in the nearby cells (including the diagonals) - The “.” (dot) represents an unknown cell: either a bomb or empty cell - If a cell contains a number (hint) then there cannot be a bomb
Minesweeper – the setup int: X = -1; % representing the unknowns in hints matrix % >= 0 for number of mines in the neighbourhood array[1..r, 1..c] of -1..8: game; % problem instance, the hints int: r = 6; % rows int: c = 6; % column game = array2d(1..r, 1..c, [ X,X,2,X,3,X, 2,X,X,X,X,X, X,X,2,4,X,3, 1,X,3,4,X,X, X,X,X,X,X,3, X,3,X,3,X,X, ]); % decision variables: 0/1 for no bomb/bomb array[1..r, 1..c] of var 0..1: mines;
Minesweeper – constraints % game[1..n, 1..n]: the given hints % mines[1..n, 1..n]: 0/1 where 1 represent a bomb % X: -1 represents the unknown constraint forall(i in 1..r, j in 1..c) ( ( (game[i,j] > X ) -> % the hint number must be the number % of all the surrounded bombs (1s) game[i,j] = sum(a,b in {-1,0,1} where i+a > 0 /\ j+b > 0 /\ i+a <= r /\ j+b <= c ) (mines[i+a,j+b]) ) /\ % if a hint, then it can't be a bomb (game[i,j] > X -> mines[i,j] = 0) ) ;
Minesweeper Declarative aspect of Constraint Programming The ideal: - Just state the requirements (the constraints) - It's now up to the CP solver to find the solution. % ... % the hint number must be the number % of all the surrounded bombs game[i,j] = sum(a,b in {-1,0,1} where i+a > 0 /\ j+b > 0 /\ i+a <= r /\ j+b <= c ) (mines[i+a,j+b]) % ...
Minesweeper - Solution ..2.3. 2..... ..24.3 1.34.. .....3 .3.3.. 100001 % 1: Bomb, 0: no bomb 010110 000010 000010 011100 100011
Key concepts in CP modelling Some of the most important - and IMHO the most fascinating - concepts in CP regarding the modelling: - Global constraints - Symmetry breaking - Element - Reification (logical relations between constraints) - Bi-directedness (reversibility, multiple flow pattern) - Channelling (dual views) - Symmetry breaking - 1/N/All solutions
Global constraints - “Patterns” in modelling problems - Constraint for arrays and variable arguments - Much research are focused on effective global constraints - Often much faster than basic constraints (all_different vs. collection of '!=') - Global Constraint Catalog, describes >400 global constraints http://sofdem.github.io/gccat/ Some of the most common global constraints: - All different: all elements must be distinct - All different except 0: all elements != 0 must be distinct - Element: indexing with decision variables - Global Cardinality Count: count occurrences of values - Decrease/Increase: ensure sortedness - Cumulative: for scheduling - Circuit: Hamiltonian circuit - Table: Allowed assignments Decompositions: http://hakank.org/minizinc/#global (~170 decompositions)
Element constraint (z = x[y]) One of the most common – and important - constraint: - z = x[y], where the index (y) is a decision variable % MiniZinc array[1..4] of var 1..4: x; var 1..4: y; var 1..4: z; constraint z = x[y]; % example A, z unknown: z = x[y] % x = [4,3,1,2] % y = 2 % -> z = 3 % example B, y unknown: z = x[y] % x = [4,3,1,2] % z = 1 % -> y = 3
Reification Reification: truth values of constraints - implication: C => b: If constraint C holds then BoolVar b = 1 else b = 0. - equivalence: C1 <=> C2: If constraint C1 holds then C2 also holds (and vice versa) - C1 and C2, C1 or C2, not C1, (C1 xor C2) Some examples (in MiniZinc syntax): - x and y are var int (domain 1..10) - b1 and b2 are var boolean (0..1) (x = y) -> (b1 = 1) % implication (x > 4) -> (y <= 4) % implication b1 <-> not(b2) % equivalence (x = 1 /\ y = 1) <-> (b1 = b2) % AND, equivalence
Reification – alldifferent_except_0 The global constraint alldifferent_except_0 is quite useful: All variables that are != 0 must be distinct. Applications: - 0 as a “dummy” value in an array (of decision variables) Decomposition using reifications: predicate alldifferent_except_0(array[int] of var int: x)= forall(i,j in index_set(x) where i < j) ( (x[i] != 0 /\ x[j] != 0) -> x[i] != x[j] ) ;
Reversibility - “bi-direction” Cf Prolog where a predicate can have variables that may be either input, output or both (“multiple flow pattern”). Simple example: - converting a number (variable) TO/FROM its digits (array) given a base
Reversibility - converting a number (variable) TO/FROM its digits (array) given a base function var int: to_num_base(array[int] of var int: a, int: base) = let { int: len = length(a); var int: n = sum(i in index_set(a)) ( pow(base, len-i) * a[i] ); } in n % n is the “return” value ; % n = 532 <==> a = [5,3,2], i.e. [5*100,3*10,2*1]
Reversibility – “dual view” - converting a number (variable) TO/FROM its digits (array) given a base We can now add constraints on either n or x: - a “dual view” on two different representations Example: int: m = 5; array[1..m] of var 0..9: x; var 0..pow(10,m)-1: n; constraint n = to_num(x) /\ all_different(x) /\ x[3] = 4 /\ n >= 50000 ; The ability to add constraints quite easily to a model is one of the strengths of CP.
Symmetry breaking A CP model is - under the hood - a search tree. A common technique to reduce a large search tree is to use SYMMETRY BREAKING. Some standard global constraints for symmetry breaking (sortedness): - increasing/decreasing: the array must be sorted - lex_less(x, y): array x is lexicographic less then array y - lex2(matrix): all rows and columns must be in lexicographic order - increasing_except_0: all values except 0 must be sorted Special forms: - x[1] < x[n] - Magic square - Frénicle standard form: constraint minimum(x[1,1], [x[1,1], x[1,n], x[n,1], x[n,n]]) /\ x[1,2] < x[2,1] ;
1/N/All solution(s) and optimal solution Most CP solvers can show any number of solutions. - First solution: just any valid solution (schedule/seating/etc). - N solutions, e.g. N=2 to check if/ensure that there are > 1 solutions. * Sudoku: must be unique solution The model is wrong if 2 solutions are printed. - All solutions * Debugging aid: N-queens for N=8 should yield 92 solutions * In mathematical problems, the number of solutions give clues to the structure. (Online Encyclopedia of Integer Sequences: http://oeis.org/) - Optimal solution Important in industrial applications (as well as some puzzles)
Constraint Programming – not a silver bullet Pros: - Excellent tool for modeling certain type of combinatorial problems - Modelling language syntax is often high or very high - Easy to add new constraints. Cons: - It takes time to model a problem, often with much experiments, especially to get search strategies right: art not science - Requires a different mind set - Debugging can be harder than in non-CP programming - Can be hard to translate traditional algorithms/data structures to a CP model.
Thank you! - Questions? Håkan Kjellerstrand (hakank@gmail.com) http://hakank.org/ My Constraint Programming Blog: http://hakank.org/constraint_programming_blog/ Constraint Programming: http://hakank.org/constraint_programming/ My GitHub page: https://github.com/hakank/hakank/
Minesweeper – search strategies To ensure the best/good performance, search strategies (heuristics) are used: - variable selection: which variable to test (in the search tree traversal) -value selection: which value to try on the selected variable Selecting the best strategy is an art - not an science - and often requires much experimentation. Example: solve :: int_search( [mines[i,j]|i in 1..r,j in 1..c], first_fail, indomain_min, complete) satisfy;
What have I NOT talked about? Advanced features in CP: - how search heuristics and propagation really works - set variables (can be very handy) - float variables - advanced examples - working of a CP solver: * parsing * propagators * search tree * etc
CP - Swedish terms This talk will be in Swedish. Here is a translation of “CP English” to Swedish. Most English terms are actually used in the Swedish discourse. - Constraint Programming: villkorsprogrammering - Constraints: villkor - Decision variables: beslutsvariabler - (Finite) domains: (finit) domän - Search tree: sökträd - Propagator/propagate: propagerare/propagera - (CP) Solver: (CP) lösare Modelling: - Global constraints: global constraints (perhaps “globala villkor”) - Search strategies (heuristics): sökstrategier (heuristiker) - Reification: reifikation - Reversibility: reversibilitet - Symmetry breaking: symmetribrytning - Dual view: “variabelkoppling”(?)
Element constraint (z = x[y]) Most CP solvers don't have support for the direct syntax as MiniZinc. Instead: - z = element(x, y) - z = x.element(y) - element(x,y,z) Element in other CP systems: # Google or-tools/Python solver.Add(z == solver.Element(x, y)) // Google or-tools/C# solver.Add(z == x.Element(y)); // Google or-tools/Java solver.addConstraint( solver.makeEquality(z, solver.makeElement(x, y).var()));
Langford problem (element, symmetry breaking, dual view) Langford problem: Arrange 2 sets of positive integers 1..k to a sequence, such that, following the first occurrence of an integer i, each subsequent occurrence of i, appears i+1 indices later than the last. For example, for k=4, a solution would be 41312432 CSPLIB Problem 24: http://www.csplib.org/prob/prob024/
Langford problem (element, symmetry breaking, dual view) int: k = 4; set of int: pos_domain = 1..2*k; % position domain array[pos_domain] of var pos_domain: pos; % dual array[pos_domain] of var 1..k: sol; % for presentation constraint forall(i in 1..k) ( pos[i+k] = pos[i] + i+1 /\ sol[pos[i]] = i /\ % element sol[pos[k+i]]= i % element ) /\ all_different(pos) /\ sol[1] < sol[2*k] % symmetry breaking ; % unique solution: % position: [2, 5, 3, 1, 4, 8, 7, 6] % solution: [4, 1, 3, 1, 2, 4, 3, 2]
Reification – alldifferent_except_0 (or-tools/C#) In Google or-tools one have to use Boolean algebra. public static void AllDifferentExcept0(Sol s, IntVar[] a) { int n = a.Length; for(int i = 0; i < n; i++) { for(int j = 0; j < i; j++) { // Boolean algebra: (b1 <= b2) s.Add((a[i] != 0) * (a[j] != 0) <= (a[i] != a[j])); } } } Note: Most (other) CP solvers have some direct syntax for reifications.
Minesweeper – other implementations Implementations of Minesweeper using the same (as possible) approach: http://hakank.org/common_cp_models/#minesweeper Choco: MineSweeper.java Comet: minesweeper.co ECLiPSE: minesweeper.ecl Gecode/R: minesweeper.rb Google CP Solver/C#: minesweeper.cs Google CP Solver/Java: Minesweeper.java Google CP Solver/Python: minesweeper.py JaCoP: MineSweeper.java JaCoP/Scala: Minesweeper.scala MiniZinc: minesweeper.mzn SICStus: minesweeper.pl Essence': minesweeper.eprime Picat: minesweeper.pi Etc...